# Create and manage financial instruments Identity Management v3 This topic describes the v3 identity model. **Identity Management v3** is recommended for new integrations. Identity Management v3 is an **upcoming feature**. For information on availability, early access, or migration, please contact your Ripple representative. The supported payment corridors will be: - US • USD - EU • EUR - MX • MXN - BR • BRL - CO • COP - CA • CAD - GB • GBP - Africa • GHS, NGN, RWF, UGX, ZAR, ZMW This tutorial shows how to use the **Identity Management v3** financial instrument endpoints to: - Create a financial instrument for an identity - List an identity’s financial instruments - Retrieve a financial instrument by ID - Update financial instrument details - Deactivate a financial instrument It assumes you’ve read [Financial instruments](/products/payments-direct-2/api-docs/concepts/financial-instruments) for payments and [Payment identities](/products/payments-direct-2/api-docs/concepts/payment-identities). Multiple instruments per identity In Identity Management v3, an identity can have **one or more financial instruments**, allowing a single party (identity) to hold multiple bank accounts or payout rails. ## Before you begin To follow these examples, you need: - Base URL for the Ripple Payments Direct 2.0 API (for example,` https://{base-url}`) - A valid OAuth2 access token with scopes: - `participants:create` – create financial instruments - `participants:read` – list and get financial instruments - `participants:update` – update and deactivate financial instruments - An existing `identityId` (created via the identities endpoints) In all examples, replace: - `{base-url}` with your PII base URL - `` with a valid access token - `{identity-id} `and `{financial-instrument-id}` with real IDs from your environment ## Create a financial instrument Use `POST /v3/identities/{identity-id}/financial-instruments` to create a financial instrument for an existing identity. You must provide: - `financialInstrumentType` – the rail, such as `US_ACH`, `MX_SPEI`,` BR_PIX` - `currency` – ISO 4217 currency code (for example, `USD`, `MXN`, `BRL`) - Exactly one rail-specific object (for example, `usAch`, `mxSpei`, `brPix`) with the required account details - Optional metadata such as `label` ### Example: Create a US ACH bank account ```bash curl -X POST "https://{base-url}/v3/identities/{identity-id}/financial-instruments" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "financialInstrumentType": "US_ACH", "currency": "USD", "label": "US bank account", "usAch": { "bankName": "Bank of Example", "bankRoutingNumber": "266231608", "accountNumber": "60480", "accountType": "CHECKING" } }' ``` ### Response (201 Created) ```json { "financialInstrumentId": "2f4ac57f-c5ba-4051-b51f-b3565778717b" } ``` You’ll use this `financialInstrumentId` when: - Getting the instrument by ID - Updating or deactivating the instrument - Referencing it in payment creation flows ### Example: Create an MX SPEI bank account for the same identity ```bash curl -X POST "https://{base-url}/v3/identities/{identity-id}/financial-instruments" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "financialInstrumentType": "MX_SPEI", "currency": "MXN", "label": "MXN SPEI account", "mxSpei": { "bankName": "Banco Ejemplo", "clabe": "032180000118359719" } }' ``` Now the same identity holds **two financial instruments** (one US ACH, one MX SPEI). Missing or invalid fields If required fields are missing or invalid (for example, CLABE length or routing code format), the API returns **400 Bad Request** with details about the failing fields. If the `identity-id` does not exist, the API returns **404 Not Found**. ### Identity validation and `validatePayoutRails` When you create a financial instrument, the associated identity must have all required PII for the specified `financialInstrumentType`. **If the identity was created with `validatePayoutRails`:** - The identity's PII was already validated against the specified payout rails at identity creation time. - Creating a financial instrument for a rail listed in `validatePayoutRails` succeeds immediately (assuming the identity has the required PII). - Creating a financial instrument for a rail **not** listed in `validatePayoutRails` triggers validation at instrument creation time. If required PII is missing, the request fails with **400 Bad Request**. **If the identity was created without `validatePayoutRails`:** - The identity's PII is validated when you create the financial instrument. - If required fields are missing for the specified `financialInstrumentType`, the request fails with **400 Bad Request** and details about which fields are missing. **Example: Validation failure due to missing PII** If you try to create a `US_ACH` financial instrument for an identity that's missing required fields like `dateOfBirth` or `identityDocuments`, you'll receive: ```json { "code": "VALIDATION_ERROR", "title": "Identity validation failed", "description": "The identity is missing required fields for the specified financial instrument type.", "details": [ { "field": "individual.dateOfBirth", "message": "Date of birth is required for US_ACH beneficiary identities" }, { "field": "individual.identityDocuments", "message": "At least one identity document (SSN or Tax ID) is required for US_ACH beneficiary identities" } ] } ``` To fix this, update the identity with the missing PII fields using `PUT /v3/identities/{identity-id}`, then retry creating the financial instrument. Upfront validation Using `validatePayoutRails` when creating identities helps catch PII issues early, before you attempt to create financial instruments. For details, see [Validating identities for specific payout rails](/products/payments-direct-2/api-docs/concepts/payment-identities#validating-identities-for-specific-payout-rails). ## List financial instruments for an identity Use `GET /v3/identities/{identity-id}/financial-instruments` to list financial instruments for an identity. Query parameters: - `version` – optional identity version. If omitted, the latest identity version is used. - `limit` – maximum number of instruments to return (1–100, default 10). - `next-token` – pagination token from a previous response. ### Example: List instruments for an identity ```bash curl -X GET "https://{base-url}/v3/identities/{identity-id}/financial-instruments?limit=10" \ -H "Authorization: Bearer " ``` ### Response (200 OK) ```json { "data": [ { "financialInstrumentId": "2f4ac57f-c5ba-4051-b51f-b3565778717b", "financialInstrumentType": "US_ACH", "currency": "USD", "label": "US bank account", "country": "US", "createdAt": "2025-10-01T18:46:47.430Z", "updatedAt": "2025-10-01T18:46:47.430Z" }, { "financialInstrumentId": "9e267ec3-0f75-4e8b-93b2-bf7e2f2a9e0d", "financialInstrumentType": "MX_SPEI", "currency": "MXN", "label": "MXN SPEI account", "country": "MX", "createdAt": "2025-10-01T18:50:12.100Z", "updatedAt": "2025-10-01T18:50:12.100Z" } ], "nextToken": "eyJrZXkxIjoidmFsdWVfMSIsImtleTIiOiJ2YWx1ZTIifQ==" } ``` - The data array can contain **multiple** instruments for the same identity. - Only metadata is returned; rail-specific objects (such as `usAch` or `mxSpei`) are not included. - If `nextToken` is present, pass it as `next-token` to fetch the next page: ```bash curl -X GET "https://{base-url}/v3/identities/{identity-id}/financial-instruments?limit=10&next-token=eyJrZXkxIjoidmFsdWVfMSIsImtleTIiOiJ2YWx1ZTIifQ==" \ -H "Authorization: Bearer " ``` If the identity or instruments are not found, the API returns **404 Not Found**. ## Get a financial instrument by ID Use `GET /v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}` to retrieve full details for a specific financial instrument, including the rail-specific object. ###Example: Get a US ACH financial instrument ```bash curl -X GET "https://{base-url}/v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}" \ -H "Authorization: Bearer " ``` ### Response (200 OK) ```json { "financialInstrument": { "country": "US", "financialInstrumentId": "7f2bac05-42a3-4b26-89fd-333396fdba70", "createdAt": "2025-10-01T18:46:47.430Z", "updatedAt": "2025-10-01T18:46:47.430Z", "usAch": { "bankName": "Bank of Example", "bankRoutingNumber": "266231608", "accountNumber": "60480", "accountType": "CHECKING" }, "currency": "USD", "label": "US bank account", "financialInstrumentType": "US_ACH" } } ``` Errors If either the `identity-id` or `financial-instrument-id` is invalid or does not exist, the API returns **400** or **404** respectively. ## Update a financial instrument Use `PUT /v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}` to update editable fields of an existing financial instrument. **You can:** - Update metadata such as label. - Update rail-specific details, such as account number or PIX key. **You cannot change:** - `financialInstrumentType` - `currency` ### Partial updates The request supports partial updates: - Fields you include are **overwritten**. - Fields you omit remain **unchanged**. ### Example: Update only the label ```bash curl -X PUT "https://{base-url}/v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "label": "US bank account (primary)" }' ``` ### Response (200 OK) ```json { "financialInstrumentId": "7f2bac05-42a3-4b26-89fd-333396fdba70", "financialInstrumentType": "US_ACH", "currency": "USD", "label": "US bank account (primary)", "country": "US", "createdAt": "2025-10-01T18:46:47.430Z", "updatedAt": "2025-10-02T09:15:10.000Z" } ``` Response The update response returns the **instrument entry** (metadata + timestamps) but does **not** include the rail-specific object (such as `usAch`). ### Example: Update rail-specific details (US ACH) ```bash curl -X PUT "https://{base-url}/v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "usAch": { "bankName": "Bank of Example", "bankRoutingNumber": "266231608", "accountNumber": "987654321", "accountType": "CHECKING" }' ``` Errors If the update payload is invalid (for example, unsupported account type or invalid routing format), the API returns **400 Bad Request** with error details. If the identity or instrument is not found, the API returns **404 Not Found**. If there is a conflicting resource state (for example, concurrent update or other internal constraint), the API may return **409 Conflict**. ## Deactivate a financial instrument Use `DELETE /v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}` to deactivate a financial instrument. **Deactivation:** - Is **permanent** for that instrument. - Prevents the instrument from being used for **new payments**. - Keeps historical usage and data for audit and reconciliation. Identity deactivation Deactivating an identity (via the identities endpoints) also deactivates its financial instrument. ### Example: Deactivate a financial instrument ```bash curl -X DELETE "https://{base-url}/v3/identities/{identity-id}/financial-instruments/{financial-instrument-id}" \ -H "Authorization: Bearer " ``` ### Response (204 No Content) The following errors may occur: - **400 Bad Request** – malformed identity or instrument ID. - **404 Not Found** – the identity or instrument does not exist. - **409 Conflict** – the instrument is already deactivated or cannot be deactivated due to its current state. - **500 Internal Server Error** – unexpected server-side error. ## Error handling All financial instrument endpoints use the standard error response schema: - **code** – machine-readable error code - **title** – short description - **description** – detailed explanation and remediation hints Common scenarios: - **400** – structural validation errors (missing required fields, pattern violations, invalid enum values). - **404** – identity or financial instrument not found. - **409** – conflicting state (for example, update or deactivate not allowed). - **500** – internal processing error; if persistent, contact Ripple support. Refer to the [Error handling reference](/products/payments-direct-2/api-docs/error-codes/api-errors) in the API docs for the complete list of error codes. ## Next steps - To understand how instruments fit into the overall payout setup, see [Financial instruments](/products/payments-direct-2/api-docs/concepts/financial-instruments) for payments. - To review the KYC / PII model that instruments attach to, see [Payment identities](/products/payments-direct-2/api-docs/concepts/payment-identities). - To see how identities and financial instruments are used together when sending money, continue with the [Create a payment](/products/payments-direct-2/api-docs/tutorials/create-a-payment) tutorial.