openapi: 3.2.0 info: title: Issuance & Secondary Markets Onboarding API description: APIs to Create Individual broker dealer accounts, Trigger KYC on the investors in the account, Review account information and KYC results, View Primary offering that are available to invest and manage investments in the assets. servers: - url: https://gateway-web-api.tzero.com/app tags: - name: Onboarding description: Managing accounts and users (create account, KYC, trusted contact, financial info). paths: /pi/v1/accounts/individual: post: tags: - Onboarding summary: Onboard Individual account description: Onboard Individual with identity information. Requires agreement (terms & conditions) and transactionId. operationId: onboardIndividualAccount security: - x-api-key: [] bearerAuth: [] requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateIndividualAccountRequest' example: transactionId: a0000000-0000-0000-0000-000000000001 investor: agreement: acceptedAccountsTermsAndCondition: true termsAcceptedAt: '2025-01-28T12:00:00' eSignatureFullName: John M Doe optOutOfTrustedContact: true email: john.doe@example.com firstName: John middleName: M lastName: Doe citizenshipCountry: US taxCountry: US dateOfBirth: '1990-01-31' employment: employmentStatus: FULL_TIME_EMPLOYED employerName: Acme Corp occupation: Software Engineer physicalAddress: street: 1122 King Road street2: Apt 12 city: New York stateOrProvince: NY postalCode: '10001' country: US mailingAddress: street: 456 Oak Ave city: New York stateOrProvince: NY postalCode: '10002' country: US phoneNumbers: - countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550123' ext: '123' type: PRIMARY - countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550999' type: ALTERNATE governmentIdentifiers: - type: TIN country: US identifier: '123456789' responses: '201': description: Created content: application/json: schema: $ref: '#/components/schemas/AccountResponse' example: id: PR-1234-5678 type: INDIVIDUAL status: ACTIVE createdTs: '2025-12-11T11:30:42.534426Z' transactionId: a0000000-0000-0000-0000-000000000001 investors: - type: PRIMARY_USER id: 43XSYHc0h4aU5cxMkqhIQn email: john.doe@example.com firstName: John middleName: M lastName: Doe citizenshipCountry: US dateOfBirth: '1990-01-31' employment: employmentStatus: FULL_TIME_EMPLOYED employerName: Acme Corp occupation: Software Engineer physicalAddress: id: 2f3b2c1a-4c1b-4b1b-9d1a-111111111111 street: 1122 King Road street2: Apt 12 city: New York stateOrProvince: NY postalCode: '10001' country: US mailingAddress: id: 3a4b5c6d-7e8f-9a0b-1c2d-444444444444 street: 456 Oak Ave city: New York stateOrProvince: NY postalCode: '10002' country: US phoneNumbers: - id: 4c2d3e4f-5a6b-7c8d-9e0f-222222222222 countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550123' ext: '123' type: PRIMARY - id: 5d3e4f5a-6b7c-8d9e-0f1a-333333333333 countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550999' type: ALTERNATE governmentIdentifiers: - id: aaaaaaaa-bbbb-cccc-dddd-333333333333 type: TIN country: US identifier: '123456789' createdTs: '2025-12-11T11:30:42.534426Z' '400': description: 'Bad Request (validation failed or invalid payload). Body: `errors` array; each item has `code`, `message`, optional `field`. **Create-account business validation codes:** | Code | Meaning | |------|---------| | DATE_OF_BIRTH_REQUIRED | Date of birth is required. | | DATE_OF_BIRTH_INVALID | Date of birth format invalid; use YYYY-MM-DD. | | DATE_OF_BIRTH_IN_FUTURE | Date of birth cannot be in the future. | | DOB_NOT_ALLOWED | Date of birth not allowed; date cannot be more than 120 years in the past. | | INVESTOR_AGE_INSUFFICIENT | Investor must be at least 18 years old. | | TAX_COUNTRY_MUST_BE_US | Tax country must be US when physical address or citizenship is US. | | GOVERNMENT_IDENTIFIER_TYPE_INVALID | Gov ID type not allowed for this country (e.g. Expected TIN for US only; INTERNATIONAL_TIN or PASSPORT for non-US). | | PASSPORT_REQUIRED_FOR_NON_US | A passport is required when physical address is not in the US. | | GOVERNMENT_IDENTIFIER_COUNTRY_MISMATCH | Gov ID country must match investor''s citizenship, or address country. | | GOVERNMENT_IDENTIFIER_LENGTH_INVALID | Government identifier length invalid for type/country. | | PHYSICAL_ADDRESS_REQUIRED | Physical address is required. | | CITIZENSHIP_COUNTRY_INVALID | Citizenship country must be two-letter ISO code. | | TAX_COUNTRY_INVALID | Tax country must be two-letter ISO code. | | ADDRESS_COUNTRY_INVALID | Address country must be two-letter ISO code. | | EMAIL_REQUIRED, EMAIL_INVALID | Email required / invalid format. | | FIRST_NAME_REQUIRED, LAST_NAME_REQUIRED | Name fields required. | | ACCOUNT_EMAIL_ALREADY_EXISTS | An account with this email already exists. | ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: dateOfBirth: summary: DoB validation (dateOfBirth in future) value: errors: - code: DATE_OF_BIRTH_IN_FUTURE message: Date of birth cannot be in the future field: investor.dateOfBirth jurisdiction: summary: Jurisdiction (country not allowed) value: errors: - code: JURISDICTION_COUNTRY_NOT_ALLOWED message: Country is not in the allowed list for account applications field: investor.physicalAddress.country govId: summary: Gov ID (passport required for non-US) value: errors: - code: PASSPORT_REQUIRED_FOR_NON_US message: A passport number is required when physical address is not in the US field: investor.governmentIdentifiers '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '422': description: 'Unprocessable Entity — jurisdiction not allowed. Same body as 400 (`errors` array). **Create-account jurisdiction codes (422):** | Code | Meaning | |------|---------| | JURISDICTION_COUNTRY_NOT_ALLOWED | Country is not in the allowed list for account applications. | | JURISDICTION_STATE_REQUIRED_FOR_US | State (region) is required when country is US. | | JURISDICTION_STATE_FORMAT_INVALID | State must be a two-character code when country is US. | | JURISDICTION_STATE_NOT_ALLOWED | State is not in the allowed list for account applications. | ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: jurisdictionCountry: summary: Jurisdiction country not allowed value: errors: - code: JURISDICTION_COUNTRY_NOT_ALLOWED message: Country is not in the allowed list for account applications field: investor.physicalAddress.country '500': description: Internal Server Error /pi/v1/accounts/{accountId}/users/{userId}: put: tags: - Onboarding summary: Update user of the account description: 'Updates a user on an existing account. Validates that the user belongs to the account. All request fields are optional. Provided fields that are editable are updated or overridden; omitted fields are left unchanged. For array fields such as phoneNumbers and governmentIdentifiers, the request body carries replace semantics: the array you send is the full desired set. Any existing items omitted from the array are treated as desired to be deleted. When null/absent, fields are unchanged.' operationId: updateInvestor security: - x-api-key: [] bearerAuth: [] parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 - name: userId in: path required: true description: Identity ID of the user to update (must belong to the account). schema: type: string example: 43XSYHc0h4aU5cxMkqhIQn requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateInvestorRequest' examples: updateInvestor: summary: Update investor value: transactionId: a0000000-0000-0000-0000-000000000001 investor: firstName: John middleName: M lastName: Doe citizenshipCountry: US taxCountry: US dateOfBirth: '1990-01-31' employment: employmentStatus: FULL_TIME_EMPLOYED employerName: Acme Corp occupation: Software Engineer physicalAddress: street: 1122 King Road street2: Apt 12 city: New York stateOrProvince: NY postalCode: '10001' country: US mailingAddress: street: 456 Oak Ave city: New York stateOrProvince: NY postalCode: '10002' country: US phoneNumbers: - countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550123' ext: '123' type: PRIMARY governmentIdentifiers: - type: TIN country: US identifier: '123456789' responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/InvestorUpdateResponse' example: investor: type: PRIMARY_USER id: 43XSYHc0h4aU5cxMkqhIQn email: john.doe@example.com firstName: John middleName: M lastName: Doe citizenshipCountry: US dateOfBirth: '1990-01-31' employment: employmentStatus: FULL_TIME_EMPLOYED employerName: Acme Corp occupation: Software Engineer physicalAddress: id: 2f3b2c1a-4c1b-4b1b-9d1a-111111111111 street: 1122 King Road street2: Apt 12 city: New York stateOrProvince: NY postalCode: '10001' country: US mailingAddress: id: 3a4b5c6d-7e8f-9a0b-1c2d-444444444444 street: 456 Oak Ave city: New York stateOrProvince: NY postalCode: '10002' country: US phoneNumbers: - id: 4c2d3e4f-5a6b-7c8d-9e0f-222222222222 countryCode: '1' countryCodeAlpha: US nationalNumber: '2125550123' ext: '123' type: PRIMARY governmentIdentifiers: - id: aaaaaaaa-bbbb-cccc-dddd-333333333333 type: TIN country: US identifier: '123456789' createdTs: '2025-12-11T11:30:42.534426Z' transactionId: a0000000-0000-0000-0000-000000000001 '400': description: 'Bad Request (validation / user does not belong to account / invalid payload). Body: `errors` array with `code`, `message`, optional `field`. **Update-user business validation codes:** | Code | Meaning | |------|---------| | INVESTOR_DOES_NOT_BELONG_TO_ACCOUNT | The specified user does not belong to this account. | | DATE_OF_BIRTH_INVALID, DATE_OF_BIRTH_IN_FUTURE, DOB_NOT_ALLOWED, INVESTOR_AGE_INSUFFICIENT | Same as create (DoB rules). | | TAX_COUNTRY_MUST_BE_US | Tax country must be US when physical address or citizenship is US. | | GOVERNMENT_IDENTIFIER_TYPE_INVALID | Gov ID type not allowed for this country (e.g. TIN for US only). | | PASSPORT_REQUIRED_FOR_NON_US | A passport is required when physical address is not in the US. | | GOVERNMENT_IDENTIFIER_COUNTRY_MISMATCH | Gov ID country must match user, citizenship, or address country. | | GOVERNMENT_IDENTIFIER_LENGTH_INVALID | Government identifier length invalid. | | GOVERNMENT_IDENTIFIER_AT_LEAST_ONE_REQUIRED | At least one government identifier must be retained; cannot delete all. | | FIELD_NOT_MUTABLE | Field cannot be changed (e.g. physicalAddress.country change not allowed). | | FIRST_NAME_REQUIRED, LAST_NAME_REQUIRED | When provided, must not be blank. | ' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: govIdType: summary: Gov ID type invalid (e.g. INTERNATIONAL_TIN when US) value: errors: - code: GOVERNMENT_IDENTIFIER_TYPE_INVALID message: Government Identifier type needs to be TIN for US residents. field: investor.governmentIdentifiers '401': description: Unauthorized '404': description: Not Found '500': description: Internal Server Error /pi/v1/accounts/{accountId}: get: tags: - Onboarding summary: Get account by ID operationId: getAccountById parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 security: - x-api-key: [] bearerAuth: [] responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/AccountResponse' '400': description: 'Bad Request (e.g. invalid accountId format). Body: `errors` array with `code`, `message`, optional `field`.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized '403': description: Forbidden (caller does not have access to this account). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: 'Not Found (account does not exist or caller has no access). Body: `errors` array; code typically `NOT_FOUND`.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: notFound: summary: Account not found value: errors: - code: NOT_FOUND message: 'Account not found: {accountId}' '500': description: 'Internal Server Error (e.g. account retrieval failed). Body: `errors` array; code e.g. `ACCOUNT_RETRIEVAL_FAILED`, `INTERNAL_ERROR`.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /pi/v1/accounts/{accountId}/users/{userId}/financialInfo: get: tags: - Onboarding summary: Get financial information for user description: Returns financial information (net worth, annual income) for the specified user. Validates that the user belongs to the account; caller must have access to the account. operationId: getFinancialInfo security: - x-api-key: [] bearerAuth: [] parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 - name: userId in: path required: true description: User ID must belong to the account. schema: type: string example: 43XSYHc0h4aU5cxMkqhIQn responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/FinancialInfoResponse' example: accountId: PR-1234-5678 netWorth: 500000 annualIncome: 120000 annualIncomeLastChangedTs: '2025-12-11T11:30:42.534426Z' '400': description: 'Bad Request (e.g. user does not belong to account). Body: `errors` array; code e.g. INVESTOR_DOES_NOT_BELONG_TO_ACCOUNT.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '500': description: Internal Server Error patch: tags: - Onboarding summary: Add or update financial information for user description: Add or update financial information for the specified user. Validates that the user belongs to the account; then updates only the provided fields (net worth, annual income). All request fields are optional; omitted fields are left unchanged. operationId: patchFinancialInfo security: - x-api-key: [] bearerAuth: [] parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 - name: userId in: path required: true description: User ID must belong to the account. schema: type: string example: 43XSYHc0h4aU5cxMkqhIQn requestBody: content: application/json: schema: $ref: '#/components/schemas/PatchFinancialInfoRequest' example: transactionId: a0000000-0000-0000-0000-000000000001 netWorth: 500000 annualIncome: 120000 required: true responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/FinancialInfoResponse' example: accountId: PR-1234-5678 netWorth: 500000 annualIncome: 120000 annualIncomeLastChangedTs: '2025-12-11T11:30:42.534426Z' transactionId: a0000000-0000-0000-0000-000000000001 '400': description: 'Bad Request (validation failed or user does not belong to account). Body: `errors` array; e.g. NET_WORTH_INVALID, ANNUAL_INCOME_INVALID, INVESTOR_DOES_NOT_BELONG_TO_ACCOUNT.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '500': description: Internal Server Error /pi/v1/accounts/{accountId}/trustedContact: post: tags: - Onboarding summary: Add trusted contact description: Add a trusted contact to the account's primary user. If the account already has a trusted contact, the request fails with a conflict. operationId: addTrustedContact security: - x-api-key: [] bearerAuth: [] parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 requestBody: content: application/json: schema: $ref: '#/components/schemas/TrustedContactRequest' example: transactionId: a0000000-0000-0000-0000-000000000001 email: trusted.contact@example.com firstName: Jane lastName: Contact physicalAddress: street: 456 Oak Avenue city: New York stateOrProvince: NY postalCode: '10001' country: US phoneNumber: '+12125550456' required: true responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/TrustedContactResponse' example: trustedContact: id: 7e8f9a0b-1c2d-3e4f-5a6b-777777777777 email: trusted.contact@example.com firstName: Jane lastName: Contact physicalAddress: street: 456 Oak Avenue city: New York stateOrProvince: NY postalCode: '10001' country: US phoneNumber: '+12125550456' transactionId: a0000000-0000-0000-0000-000000000001 '400': description: Bad Request (validation or trusted contact already exists). Same error body; see ErrorResponse and x-businessValidationErrorCodes in components. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '500': description: Internal Server Error /pi/v1/accounts/{accountId}/trustedContact/{trustedContactUserId}: delete: tags: - Onboarding summary: Remove trusted contact description: Remove the trusted contact from the account's primary user. The path parameter must be the identity ID of the current trusted contact. operationId: removeTrustedContact security: - x-api-key: [] bearerAuth: [] parameters: - name: accountId in: path required: true description: Account identifier. schema: type: string example: PR-1234-5678 - name: trustedContactUserId in: path required: true description: Identity ID of the trusted contact to remove (must match the account's current trusted contact). schema: type: string example: 7e8f9a0b-1c2d-3e4f-5a6b-777777777777 responses: '204': description: No Content '400': description: Bad Request (trustedContactUserId does not match account's trusted contact) '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '500': description: Internal Server Error /pi/v1/users/{userId}/kyc: get: tags: - Onboarding summary: Get KYC status for user description: 'Retrieve the KYC status for a specific user (identity ID). Returns status, and when document verification (DocV) is required, may include docUrl and qrMessage for the user to complete verification. **KYC status values:** | Status | Meaning | |--------|---------| | PENDING | KYC submitted; pending manual review or document verification. User may need to complete DocV (see docUrl/qrMessage when present). | | APPROVED | KYC approved; user is verified. | | NOT_APPROVED | KYC not approved (non-retryable). | | NOT_APPROVED_RETRYABLE | KYC not approved; user may retry. | | VENDOR_ERROR / CANNOT_PROCESS | Vendor or processing error; may retry later. | **When to expect docUrl and qrMessage:** These fields are populated when status is PENDING and document verification (DocV) is required. The client can present docUrl (link) or qrMessage (QR code image data) to the user so they can upload their ID document. When docStatus is USER_ACTION_REQUIRED, the user must complete the DocV flow; after they do, docStatus moves to PROCESSING then COMPLETED (or EXPIRED/FAILED).' operationId: getUserKycStatus security: - x-api-key: [] bearerAuth: [] parameters: - name: userId in: path required: true description: Identity (user) ID. schema: type: string example: 43XSYHc0h4aU5cxMkqhIQn responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PostKycResponse' example: userId: 43XSYHc0h4aU5cxMkqhIQn kycResult: status: APPROVED id: b1c2d3e4-f5a6-7b8c-9d0e-555555555555 createdTs: '2025-12-11T11:35:00.000000' modifiedTs: '2025-12-11T11:40:00.000000' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Forbidden (caller does not have access to this user's KYC). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: 'Not Found (no KYC record for this user, or user does not exist). Body: `errors` array; code typically `KYC_NOT_FOUND`.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' examples: kycNotFound: summary: KYC not found for user value: errors: - code: KYC_NOT_FOUND message: 'KYC not found for user: {userId}' '500': description: 'Internal Server Error (e.g. KYC retrieval failed). Body: `errors` array; code e.g. `KYC_RETRIEVAL_ERROR`, `INTERNAL_ERROR`.' content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' post: tags: - Onboarding summary: Trigger KYC for user description: Trigger a KYC check for a specific user. operationId: triggerKyc security: - x-api-key: [] bearerAuth: [] parameters: - name: userId in: path required: true description: Identity (user) ID. schema: type: string example: 43XSYHc0h4aU5cxMkqhIQn requestBody: content: application/json: schema: $ref: '#/components/schemas/TriggerKycRequest' example: transactionId: a0000000-0000-0000-0000-000000000001 required: true responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/PostKycResponse' example: userId: 43XSYHc0h4aU5cxMkqhIQn kycResult: status: PENDING id: b1c2d3e4-f5a6-7b8c-9d0e-555555555555 createdTs: '2025-12-11T11:35:00.000000' transactionId: a0000000-0000-0000-0000-000000000001 '400': description: Bad Request (validation or invalid payload) '401': description: Unauthorized '403': description: Forbidden '404': description: Not Found '500': description: Internal Server Error components: schemas: AddressResponse: type: object properties: id: type: - string - 'null' format: uuid example: 2f3b2c1a-4c1b-4b1b-9d1a-111111111111 street: type: - string - 'null' street2: type: - string - 'null' street3: type: - string - 'null' street4: type: - string - 'null' street5: type: - string - 'null' unit: type: - string - 'null' city: type: - string - 'null' stateOrProvince: type: - string - 'null' description: State or province. postalCode: type: - string - 'null' country: type: - string - 'null' createdTs: type: - string - 'null' format: date-time modifiedTs: type: - string - 'null' format: date-time TrustedContactAddress: type: object properties: street: type: string street2: type: - string - 'null' city: type: string stateOrProvince: type: string description: State or province. postalCode: type: string country: type: string FinancialInfoResponse: type: object properties: accountId: type: string description: Account identifier. netWorth: type: - number - 'null' format: decimal annualIncome: type: - number - 'null' format: decimal annualIncomeLastChangedTs: type: - string - 'null' format: date-time transactionId: type: - string - 'null' description: Echoed from request on PATCH; null on GET. InvestmentProfile: type: object required: - investmentObjective - tradeIlliquidSecurities properties: investmentObjective: $ref: '#/components/schemas/InvestmentObjective' tradeIlliquidSecurities: type: boolean description: Acknowledgement that user is willing to trade low volume securities. ErrorResponse: type: object description: Error response body for validation and business-rule failures. Contains a list of errors; each item has code, message, and optional field (JSON path). properties: errors: type: array items: $ref: '#/components/schemas/ErrorItem' TrustedContactResponse: type: object properties: trustedContact: $ref: '#/components/schemas/TrustedContactDetails' description: The created trusted contact. transactionId: type: - string - 'null' description: Echoed from the request. TermsAcceptRequest: type: object required: - acceptedAccountsTermsAndCondition - eSignatureFullName properties: acceptedAccountsTermsAndCondition: type: boolean description: Must be true to accept account terms and conditions. termsAcceptedAt: type: - string - 'null' format: date-time description: Timestamp when terms were accepted (ISO-8601); if null, current time is used. eSignatureFullName: type: string minLength: 1 maxLength: 300 description: E-signature (full name including middle name when present); must match investor's full name. PatchFinancialInfoRequest: type: object description: All fields optional except transactionId; only provided fields are updated. required: - transactionId properties: transactionId: type: string description: Mandatory string for auditing and troubleshooting; echoed back in the response. example: a0000000-0000-0000-0000-000000000001 netWorth: type: - number - 'null' format: decimal minimum: 0 description: Net worth; when provided, updates primary user's net worth. annualIncome: type: - number - 'null' format: decimal minimum: 0 description: Annual income; when provided, updates primary user's annual income. PhoneNumberResponse: type: object properties: id: type: - string - 'null' format: uuid example: 4c2d3e4f-5a6b-7c8d-9e0f-222222222222 countryCode: type: - string - 'null' countryCodeAlpha: type: - string - 'null' nationalNumber: type: - string - 'null' ext: type: - string - 'null' type: $ref: '#/components/schemas/PhoneNumberType' createdTs: type: - string - 'null' format: date-time modifiedTs: type: - string - 'null' format: date-time EmploymentStatus: type: string enum: - FULL_TIME_EMPLOYED - PART_TIME_EMPLOYED - UNEMPLOYED - RETIRED - STUDENT description: Case-insensitive when deserializing. AddressRequest: type: object required: - street - city - stateOrProvince - postalCode - country properties: street: type: string example: 1122 King Road street2: type: - string - 'null' example: Apt 12 street3: type: - string - 'null' street4: type: - string - 'null' street5: type: - string - 'null' unit: type: - string - 'null' example: Unit 5B city: type: string example: New York stateOrProvince: type: string description: State or province (required for address). example: NY postalCode: type: string example: '10001' country: type: string description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US PostKycResponse: type: object properties: userId: type: string kycResult: $ref: '#/components/schemas/KycResponse' transactionId: type: - string - 'null' description: Echoed from the request. GovernmentIdentifierType: type: string enum: - TIN - INTERNATIONAL_TIN - PASSPORT - EIN example: TIN CreateIndividualAccountRequest: type: object required: - transactionId - investor properties: transactionId: type: string description: Mandatory string for auditing and troubleshooting; echoed back in the response. example: a0000000-0000-0000-0000-000000000001 investor: $ref: '#/components/schemas/InvestorRequest' optOutOfTrustedContact: type: boolean description: Account owner intending to not add a trusted contact to the account.If the owner agrees to add trusted contact then the trustedContact is required while creating an account. investmentProfile: allOf: - $ref: '#/components/schemas/InvestmentProfile' trustedContact: allOf: - $ref: '#/components/schemas/AccountTrustedContact' InvestorUpdateResponse: type: object description: Updated investor. properties: investor: $ref: '#/components/schemas/InvestorResponse' transactionId: type: - string - 'null' description: Echoed from the request on PUT. TriggerKycRequest: type: object required: - transactionId properties: transactionId: type: string description: Mandatory string for auditing and troubleshooting; echoed back in the response. example: a0000000-0000-0000-0000-000000000001 GovernmentIdentifierResponse: type: object properties: id: type: - string - 'null' format: uuid example: aaaaaaaa-bbbb-cccc-dddd-333333333333 type: $ref: '#/components/schemas/GovernmentIdentifierType' country: type: string example: US identifier: type: - string - 'null' example: '123456789' createdTs: type: - string - 'null' format: date-time modifiedTs: type: - string - 'null' format: date-time AccountResponse: type: object properties: id: type: string type: type: string status: type: string createdTs: type: string format: date-time investors: type: array description: Investors associated to the account. items: $ref: '#/components/schemas/InvestorResponse' optOutOfTrustedContact: type: boolean description: Captured Account owner response regarding addition of Trusted contact to the account. trustedContact: allOf: - $ref: '#/components/schemas/TrustedContactDetails' description: Account's trusted contact when set; null otherwise (trusted contact is not an investor). example: id: 7e8f9a0b-1c2d-3e4f-5a6b-777777777777 email: trusted.contact@example.com firstName: Jane lastName: Contact physicalAddress: street: 456 Oak Avenue city: New York stateOrProvince: NY postalCode: '10001' country: US phoneNumbers: '+12125550456' transactionId: type: - string - 'null' description: Echoed from the request on POST/PUT; null on GET. TrustedContactRequest: type: object required: - transactionId - email - firstName - lastName - physicalAddress properties: transactionId: type: string description: Mandatory string for auditing and troubleshooting; echoed back in the response. example: a0000000-0000-0000-0000-000000000001 email: type: string format: email firstName: type: string minLength: 1 maxLength: 100 middleName: type: - string - 'null' lastName: type: string minLength: 1 maxLength: 100 physicalAddress: $ref: '#/components/schemas/TrustedContactAddress' phoneNumber: type: string AccountTrustedContact: type: object required: - email - firstName - lastName - physicalAddress - phoneNumber properties: email: type: string format: email firstName: type: string minLength: 1 maxLength: 100 middleName: type: - string - 'null' lastName: type: string minLength: 1 maxLength: 100 physicalAddress: $ref: '#/components/schemas/TrustedContactAddress' phoneNumber: type: string TrustedContactDetails: type: object description: Trusted contact. properties: id: type: - string - 'null' email: type: string firstName: type: string middleName: type: - string - 'null' lastName: type: string physicalAddress: allOf: - $ref: '#/components/schemas/TrustedContactAddress' phoneNumber: type: string ErrorItem: type: object properties: code: type: string description: Error/validation code (e.g. DATE_OF_BIRTH_IN_FUTURE, JURISDICTION_COUNTRY_NOT_ALLOWED). See x-businessValidationErrorCodes for business logic codes. message: type: string description: Human-readable message. field: type: - string - 'null' description: Request field path when applicable (e.g. investor.dateOfBirth, investor.physicalAddress.country). details: type: - object - 'null' additionalProperties: true description: 'Optional object that will be sent for certain error `code` and documented in the endpoint''s error table. ' PhoneNumberType: type: string enum: - PRIMARY - ALTERNATE example: PRIMARY InvestmentObjective: type: string enum: - CAPITAL_APPRECIATION - SPECULATION - TRADING_PROFITS description: Case-insensitive when deserializing. PhoneNumberRequest: type: object properties: countryCode: type: - string - 'null' example: '1' countryCodeAlpha: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US nationalNumber: type: - string - 'null' example: '2125550123' ext: type: - string - 'null' example: '123' type: $ref: '#/components/schemas/PhoneNumberType' GovernmentIdentifierRequest: type: object properties: type: $ref: '#/components/schemas/GovernmentIdentifierType' country: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US identifier: type: - string - 'null' example: '123456789' EmploymentResponse: type: object properties: employmentStatus: $ref: '#/components/schemas/EmploymentStatus' employerName: type: - string - 'null' occupation: type: - string - 'null' InvestorRequest: type: object required: - agreement - email - firstName - lastName - physicalAddress - dateOfBirth properties: agreement: $ref: '#/components/schemas/TermsAcceptRequest' description: Terms and conditions acceptance; required. email: type: string format: email example: john.doe@example.com firstName: type: string minLength: 1 maxLength: 100 example: John middleName: type: - string - 'null' example: M lastName: type: string minLength: 1 maxLength: 100 example: Doe citizenshipCountry: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US taxCountry: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US dateOfBirth: type: string description: ISO date YYYY-MM-DD required. example: '1990-01-31' employment: $ref: '#/components/schemas/EmploymentRequest' physicalAddress: $ref: '#/components/schemas/AddressRequest' mailingAddress: allOf: - $ref: '#/components/schemas/AddressRequest' phoneNumbers: type: array items: $ref: '#/components/schemas/PhoneNumberRequest' governmentIdentifiers: type: array items: $ref: '#/components/schemas/GovernmentIdentifierRequest' InvestorUpdateRequest: type: object description: 'Investor update payload. Notes: - Email cannot be changed after account creation (if provided it may be rejected). - dateOfBirth is optional; when provided (YYYY-MM-DD), validated for format, not future, not older than 120y, min age 18. - firstName/lastName when provided must not be blank. - phoneNumbers uses replace semantics when provided (full desired set). - governmentIdentifiers supports replace semantics when provided. - Country/residence is derived from physicalAddress.country only. ' properties: firstName: type: - string - 'null' minLength: 1 maxLength: 100 example: John middleName: type: - string - 'null' example: M lastName: type: - string - 'null' minLength: 1 maxLength: 100 example: Doe citizenshipCountry: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US taxCountry: type: - string - 'null' description: ISO 3166-1 alpha-2 country code (two uppercase letters). example: US dateOfBirth: type: - string - 'null' description: Investor's date of birth; ISO date YYYY-MM-DD. Optional; when provided, same validation as create. example: '1990-01-31' employment: $ref: '#/components/schemas/EmploymentRequest' physicalAddress: allOf: - $ref: '#/components/schemas/AddressRequest' mailingAddress: allOf: - $ref: '#/components/schemas/AddressRequest' phoneNumbers: type: - array - 'null' description: 'Replace semantics when provided: this list is the full desired set; omitted existing phones are deleted. When null/absent, phones are unchanged. ' items: $ref: '#/components/schemas/PhoneNumberRequest' governmentIdentifiers: type: - array - 'null' description: 'Replace semantics when provided: this list is the full desired set; omitted existing identifiers are deleted. At least one identifier must remain if the account has existing identifiers (cannot delete all). When null/absent, government identifiers are unchanged. ' items: $ref: '#/components/schemas/GovernmentIdentifierRequest' InvestorResponse: type: object properties: type: type: - string - 'null' id: type: - string - 'null' email: type: - string - 'null' firstName: type: - string - 'null' middleName: type: - string - 'null' lastName: type: - string - 'null' citizenshipCountry: type: - string - 'null' dateOfBirth: type: - string - 'null' employment: allOf: - $ref: '#/components/schemas/EmploymentResponse' physicalAddress: allOf: - $ref: '#/components/schemas/AddressResponse' mailingAddress: allOf: - $ref: '#/components/schemas/AddressResponse' phoneNumbers: type: array items: $ref: '#/components/schemas/PhoneNumberResponse' governmentIdentifiers: type: array items: $ref: '#/components/schemas/GovernmentIdentifierResponse' UpdateInvestorRequest: type: object required: - transactionId - investor properties: transactionId: type: string description: Mandatory string for auditing and troubleshooting; echoed back in the response. example: a0000000-0000-0000-0000-000000000001 investor: $ref: '#/components/schemas/InvestorUpdateRequest' KycResponse: type: object properties: status: type: - string - 'null' description: 'KYC status. Values: PENDING (submitted, awaiting review or DocV), APPROVED (verified), NOT_APPROVED (denied, non-retryable), NOT_APPROVED_RETRYABLE (denied, may retry), VENDOR_ERROR, CANNOT_PROCESS. When PENDING and DocV is required, docUrl and qrMessage may be present for the user to complete document verification. ' id: type: - string - 'null' format: uuid description: KYC record ID. createdTs: type: - string - 'null' format: date-time modifiedTs: type: - string - 'null' format: date-time docUrl: type: - string - 'null' description: 'Present when status is PENDING and document verification (DocV) is required and the link is valid. URL for the user to upload their ID document. Omit or null when DocV is not required or link has expired. ' qrMessage: type: - string - 'null' description: 'Present when status is PENDING and DocV is required and the link is valid. Base64 or image data for a QR code that points to the same document-upload flow as docUrl. Use when showing the user a QR code instead of a link. Omit or null when DocV is not required or link has expired. ' docStatus: type: - string - 'null' description: 'Document verification (DocV) status. Null when no DocV request exists. Values: USER_ACTION_REQUIRED (user must complete DocV; docUrl/qrMessage are present when valid), PROCESSING (document received, verification in progress), COMPLETED (DocV succeeded), EXPIRED (link or session expired), FAILED (verification failed). ' EmploymentRequest: type: object required: - employmentStatus properties: employmentStatus: $ref: '#/components/schemas/EmploymentStatus' employerName: type: - string - 'null' maxLength: 100 description: Required when employmentStatus is FULL_TIME_EMPLOYED or PART_TIME_EMPLOYED. occupation: type: - string - 'null' maxLength: 100 description: Required when employmentStatus is FULL_TIME_EMPLOYED or PART_TIME_EMPLOYED. securitySchemes: x-api-key: type: apiKey in: header name: x-apikey bearerAuth: type: http scheme: bearer bearerFormat: JWT refreshToken: type: refreshToken in: header name: refreshToken