{
  "openapi": "3.1.0",
  "info": {
    "title": "B2B API",
    "description": "RAI Partners B2B API",
    "license": {
      "name": "Proprietary — © RAI Partners Inc. All rights reserved.",
      "url": "https://www.raipartners.com"
    },
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://api.raipartners.com/b2b",
      "description": "Production"
    },
    {
      "url": "https://api.dev.raipartners.com/b2b",
      "description": "Sandbox"
    }
  ],
  "tags": [
    {
      "name": "Profile",
      "description": "Profile functions"
    },
    {
      "name": "Authentication",
      "description": "Authentication functions"
    }
  ],
  "paths": {
    "/auth/client-secret/rotation": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Rotates and returns the client secret",
        "description": "Rotates and returns the client secret",
        "operationId": "rotateClientSecret",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "The rotated secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotatedSecret"
                }
              }
            }
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Generic invalid data": {
                    "description": "Generic invalid data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more fields are invalid."
                    }
                  },
                  "Generic missing data": {
                    "description": "Generic missing data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:missing-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more required fields are missing."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Unauthorized": {
                    "description": "Unauthorized",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:authorization:unauthorized",
                      "title": "Unauthorized",
                      "status": 401,
                      "detail": "You are not authorized to perform this action."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Forbidden": {
                    "description": "Forbidden",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:authorization:forbidden",
                      "title": "Forbidden",
                      "status": 403,
                      "detail": "You are forbidden to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Not found": {
                    "description": "Not found",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Resource not found."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Internal server error": {
                    "description": "Internal server error",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Internal Server Error",
                      "status": 500,
                      "detail": "An unexpected error occurred."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Service unavailable": {
                    "description": "Service unavailable",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Service unavailable Error",
                      "status": 503,
                      "detail": "Service is unavailable."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer-jwt": []
          }
        ]
      }
    },
    "/auth/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Authenticate client",
        "description": "Authenticate a client and retrieve the JWT token",
        "operationId": "authenticateClient",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptVersion"
          }
        ],
        "requestBody": {
          "description": "The client credentials.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The JWT token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JWTClientTokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Generic invalid data": {
                    "description": "Generic invalid data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more fields are invalid."
                    }
                  },
                  "Generic missing data": {
                    "description": "Generic missing data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:missing-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more required fields are missing."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Not found": {
                    "description": "Not found",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Resource not found."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Internal server error": {
                    "description": "Internal server error",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Internal Server Error",
                      "status": 500,
                      "detail": "An unexpected error occurred."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Service unavailable": {
                    "description": "Service unavailable",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Service unavailable Error",
                      "status": 503,
                      "detail": "Service is unavailable."
                    }
                  }
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/portal/profile": {
      "post": {
        "tags": [
          "Profile"
        ],
        "summary": "Create a profile after an an account is booked or with the provided information",
        "description": "Create a profile after an an account is booked or with the provided information",
        "operationId": "registerProfile",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptVersion"
          }
        ],
        "requestBody": {
          "description": "The profile registration.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProfileRegistration"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Success"
          },
          "400": {
            "description": "Bad request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Generic invalid data": {
                    "description": "Generic invalid data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more fields are invalid."
                    }
                  },
                  "Generic missing data": {
                    "description": "Generic missing data",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:missing-data",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "One or more required fields are missing."
                    }
                  },
                  "Cardholder too young": {
                    "description": "Cardholder too young",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data:too-young",
                      "title": "Too Young",
                      "status": 400,
                      "detail": "Cardholder must be at least 18 years old"
                    }
                  },
                  "Invalid account number": {
                    "description": "Invalid account number",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data",
                      "title": "Validation Error",
                      "status": 400,
                      "detail": "CardNumber must be 16 digits long, received '123456789012345'"
                    }
                  },
                  "Invalid social security number": {
                    "description": "Invalid social security number",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:validation:invalid-data",
                      "title": "Validation Error",
                      "status": 400,
                      "detail": "SocialSecurityNumber must be a 9 digit number, received '12345679'"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Unauthorized": {
                    "description": "Unauthorized",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:authorization:unauthorized",
                      "title": "Unauthorized",
                      "status": 401,
                      "detail": "You are not authorized to perform this action."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Forbidden": {
                    "description": "Forbidden",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:authorization:forbidden",
                      "title": "Forbidden",
                      "status": 403,
                      "detail": "You are forbidden to perform this action."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Not found": {
                    "description": "Not found",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:not-found",
                      "title": "Not Found",
                      "status": 404,
                      "detail": "Resource not found."
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Internal server error": {
                    "description": "Internal server error",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Internal Server Error",
                      "status": 500,
                      "detail": "An unexpected error occurred."
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetail"
                },
                "examples": {
                  "Service unavailable": {
                    "description": "Service unavailable",
                    "value": {
                      "type": "urn:raipartners:api:b2b:errors:internal",
                      "title": "Service unavailable Error",
                      "status": 503,
                      "detail": "Service is unavailable."
                    }
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "bearer-jwt": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "RotatedSecret": {
        "type": "object",
        "description": "Client rotated secret",
        "properties": {
          "secret": {
            "type": "string",
            "description": "The new client secret.",
            "example": "PX4eWb9rcRT1RBqvLw4GtuqyoUFWoGLr"
          }
        },
        "required": [
          "secret"
        ]
      },
      "ProblemDetail": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "The URI of the problem type",
            "example": "urn:raipartners:api:b2b:errors:validation:missing-data"
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "The title of the problem",
            "example": "Bad Request"
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "description": "The status code of the problem",
            "example": 400
          },
          "detail": {
            "type": [
              "string",
              "null"
            ],
            "description": "The details of the problem",
            "example": "One or more required fields are missing."
          },
          "instance": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri-reference",
            "description": "The instance of the problem",
            "example": "/account/12345/errors/abc-987"
          },
          "properties": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {},
            "description": "extra properties to enhance information about the problem"
          }
        },
        "required": [
          "status"
        ]
      },
      "ClientTokenRequest": {
        "type": "object",
        "description": "A client token request payload",
        "properties": {
          "client_id": {
            "type": "string",
            "description": "The client ID to use for authentication",
            "example": "los-client"
          },
          "client_secret": {
            "type": "string",
            "description": "The client secret to use for authentication",
            "example": "my-super-auth-secret"
          }
        },
        "required": [
          "client_id",
          "client_secret"
        ]
      },
      "JWTClientTokenResponse": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "description": "The token scope as a space delimited set of values.",
            "example": "read:user write:user"
          },
          "refresh_expires_in": {
            "type": "integer",
            "format": "int32",
            "description": "The refresh token expiry in seconds.",
            "example": 300
          },
          "token_type": {
            "type": "string",
            "description": "The token type.",
            "example": "Bearer"
          },
          "not-before-policy": {
            "type": "integer",
            "format": "int32",
            "description": "The not before policy in seconds.",
            "example": 0
          },
          "access_token": {
            "type": "string",
            "description": "The JWT token.",
            "example": "eyo....."
          },
          "expires_in": {
            "type": "integer",
            "format": "int32",
            "description": "The token expiry in seconds.",
            "example": 300
          }
        },
        "required": [
          "access_token",
          "expires_in",
          "scope",
          "token_type"
        ]
      },
      "Address": {
        "type": "object",
        "properties": {
          "line1": {
            "type": "string",
            "description": "The first line.",
            "example": "1 Main St",
            "pattern": "^(?=.*\\S).{1,26}$"
          },
          "line2": {
            "type": [
              "string",
              "null"
            ],
            "description": "The optional second line.",
            "example": "Apt 35",
            "pattern": "^(?:[a-zA-Z0-9\\s\\-.\\/,#'']{0,26}|)$"
          },
          "city": {
            "type": "string",
            "description": "The city name.",
            "example": "Dallas",
            "pattern": "\\b[A-Za-z0-9\\- ]{2,18}\\b"
          },
          "state": {
            "type": "string",
            "description": "The state abbreviation.",
            "example": "TX",
            "pattern": "^[A-Z]{2}$"
          },
          "zipCode": {
            "type": "string",
            "description": "The 5 digit zip code.",
            "example": "75000",
            "pattern": "^(\\d{5}(-\\d{4})?)|(\\d{9})$"
          }
        },
        "required": [
          "city",
          "line1",
          "state",
          "zipCode"
        ]
      },
      "Communications": {
        "type": "object",
        "properties": {
          "mobilePhone": {
            "$ref": "#/components/schemas/Phone",
            "description": "Mobile phone information"
          },
          "email": {
            "$ref": "#/components/schemas/EmailAddress",
            "description": "Email information"
          }
        },
        "required": [
          "email",
          "mobilePhone"
        ]
      },
      "EmailAddress": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "description": "The email.",
            "example": "myemail@email.com"
          },
          "verified": {
            "type": "boolean",
            "description": "Is the email verified",
            "example": true
          }
        },
        "required": [
          "address",
          "verified"
        ]
      },
      "IncomeInformation": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "integer",
            "format": "int32",
            "description": "Income in whole dollars",
            "example": 10000,
            "minimum": 1
          },
          "source": {
            "type": "string",
            "description": "The income source",
            "enum": [
              "Employment",
              "Inheritance",
              "Trust",
              "Investment",
              "Retirement",
              "SocialSecurity",
              "Unemployment",
              "Other"
            ],
            "example": "Employment"
          },
          "frequency": {
            "type": "string",
            "description": "The income frequency",
            "enum": [
              "Yearly",
              "Monthly",
              "Weekly",
              "BiWeekly",
              "SemiMonthly"
            ],
            "example": "Yearly"
          }
        },
        "required": [
          "amount",
          "frequency",
          "source"
        ]
      },
      "Name": {
        "type": "object",
        "properties": {
          "first": {
            "type": "string",
            "example": "John",
            "pattern": "^(?! )(?![ '.-])[\\w\\s./'-]{1,29}(?<! )(?<!-)$"
          },
          "last": {
            "type": "string",
            "example": "Smith",
            "pattern": "^(?! )(?![ '.-])[\\w\\s./'-]{1,29}(?<! )(?<!-)$"
          },
          "middle": {
            "type": [
              "string",
              "null"
            ],
            "example": "James",
            "pattern": "^(?! )(?![ '.-])[\\w\\s./'-]{1,29}(?<! )(?<!-)$"
          }
        },
        "required": [
          "first",
          "last"
        ]
      },
      "Person": {
        "type": "object",
        "properties": {
          "name": {
            "$ref": "#/components/schemas/Name",
            "description": "The person's name."
          },
          "dob": {
            "type": "string",
            "format": "date",
            "description": "The person's date of birth.",
            "example": "2000-01-31"
          },
          "ssn": {
            "type": "string",
            "description": "9 digits social security number.",
            "example": "123456789",
            "pattern": "\\d{9}"
          },
          "cardNumber": {
            "type": "string",
            "description": "16 digits card number.",
            "example": "1234567890123456",
            "pattern": "\\d{16}"
          },
          "communications": {
            "$ref": "#/components/schemas/Communications",
            "description": "Communication data"
          },
          "address": {
            "$ref": "#/components/schemas/Address",
            "description": "Address data"
          },
          "income": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/IncomeInformation"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "address",
          "cardNumber",
          "communications",
          "dob",
          "name",
          "ssn"
        ]
      },
      "Phone": {
        "type": "object",
        "properties": {
          "number": {
            "type": "string",
            "description": "10 digits phone number.",
            "example": "1234567890",
            "pattern": "\\d{10}"
          },
          "verified": {
            "type": "boolean",
            "description": "Is the phone verified",
            "example": true
          }
        },
        "required": [
          "number",
          "verified"
        ]
      },
      "ProfileRegistration": {
        "type": "object",
        "properties": {
          "opa": {
            "type": "string",
            "description": "16 digits OPA.",
            "example": "1234567890123456",
            "pattern": "\\d{16}"
          },
          "primaryCardholder": {
            "$ref": "#/components/schemas/Person",
            "description": "The primary cardholder information."
          },
          "secondaryCardholder": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Person"
              },
              {
                "type": "null"
              }
            ]
          },
          "authorizedUsers": {
            "type": [
              "array",
              "null"
            ],
            "description": "The optional list of authorized users.",
            "items": {
              "$ref": "#/components/schemas/Person"
            }
          }
        },
        "required": [
          "opa",
          "primaryCardholder"
        ]
      }
    },
    "parameters": {
      "AcceptVersion": {
        "name": "API-Version",
        "in": "header",
        "description": "API version — must be 1.0.0 or higher",
        "required": true,
        "schema": {
          "type": "string",
          "example": "1.0.0"
        }
      }
    },
    "securitySchemes": {
      "bearer-jwt": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    }
  }
}