This tutorial shows how to use the Identity Management v3 identity endpoints to:
- Create a new identity
- Retrieve an identity by ID (and by version)
- List identities with filters and pagination
- Update identity details
- Deactivate an identity
It builds on the model described in Payment identities and focuses on the v3 identity schema.
A key behavior in v3 is that at most one ACTIVE identity in your environment can use a given internalId. Attempts to create or update an identity so that its internalId collides with another ACTIVE identity result in 409 Conflict.
To follow these examples, you need:
- Base URL for the Identity Management (for example,
https://{base-url}) - An access token with the following scopes (or equivalent):
participants:createfor creating identitiesparticipants:readfor reading and listing identitiesparticipants:updatefor updating and deactivating identities
- The v3 identity model from Payment identities (INDIVIDUAL vs BUSINESS and ORIGINATOR vs BENEFICIARY)
In all examples below, replace:
{base-url}with your actual PII base URL<access_token>with a valid OAuth2 access token{identity-id}with a realidentityIdreturned by the API
Use POST /v3/identities to create a new identity.
At minimum, you must provide:
identityType– INDIVIDUAL or BUSINESSpaymentRole– ORIGINATOR or BENEFICIARY- Either individual or business details, depending on
identityType internalIdfor ORIGINATOR identities (required by corridor rules)
For BENEFICIARY identities, internalId is optional, but recommended if you want to link beneficiaries to your own customer records.
Identity Management v3 enforces that at most one ACTIVE identity per tenant can use a given internalId.
- If you try to create an identity and the provided
internalIdis already used by another ACTIVE identity, the request fails with 409 Conflict. - You can handle this error in your integration to surface “duplicate customer” conditions or guide users to reuse the existing identity.
Optionally, you can also:
- Set a friendly
nickNameandtags - Add
validatePayoutRailsto validate the identity against specific payout rails (for example,US_ACH,BR_PIX,MX_SPEI)
Example: Create an INDIVIDUAL ORIGINATOR
curl -X POST "https://{base-url}/v3/identities" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"identityType": "INDIVIDUAL",
"paymentRole": "ORIGINATOR",
"internalId": "customer-12345",
"nickName": "Alice Sender USD",
"tags": ["sender", "priority"],
"validatePayoutRails": ["US_ACH"],
"individual": {
"firstName": "Alice",
"lastName": "Chen",
"dateOfBirth": "1990-05-14",
"citizenship": "US",
"address": {
"streetAddress": ["123 Main Street"],
"city": "San Francisco",
"stateOrProvince": "CA",
"postalCode": "94105",
"country": "US"
}
}
}'Response (201 Created)
{
"identityId": "99254c4f-f207-4792-a846-06928825018c",
"version": "1"
}If you send another POST /v3/identities with the same internalId while this identity is still ACTIVE, the service returns:
- 409 Conflict – indicating that another ACTIVE identity already uses that
internalId.
Handle 409 as a signal that you should look up and reuse the existing identity instead of creating a duplicate.
Example: Create a BUSINESS BENEFICIARY
curl -X POST "https://{base-url}/v3/identities" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"identityType": "BUSINESS",
"paymentRole": "BENEFICIARY",
"internalId": "counterparty-7890",
"nickName": "Widgets Org MX",
"tags": ["beneficiary", "mx"],
"validatePayoutRails": ["MX_SPEI"],
"business": {
"businessName": "Widgets Org",
"incorporationCountry": "US",
"registration": [
{
"number": "123ABC",
"type": "INCORPORATION_CERTIFICATE"
}
],
"email": "fake@example.com",
"phone": "+1234567890",
"address": {
"streetAddress": ["123 Example MA"],
"city": "Boston",
"stateOrProvince": "MS",
"postalCode": "12345",
"country": "US"
}
}
}'If any required PII is missing or invalid for the rails in validatePayoutRails, the API returns a 400 error describing which fields failed validation.
Use GET /v3/identities/{identity-id} to retrieve a specific identity.
- If you omit the version query parameter, the latest version is returned.
- To retrieve a specific version, include
?version={version-number}.
Example: Get the latest version
curl -X GET "https://{base-url}/v3/identities/9d839f58-7fd3-4913-a27e-48d31973d3f9" \
-H "Authorization: Bearer <access_token>"Response (200 OK)
{
"identityId": "9d839f58-7fd3-4913-a27e-48d31973d3f9",
"identityState": "ACTIVE",
"nickName": "nickName",
"tags": ["tag1"],
"version": "2",
"schemaVersion": "1.0.0",
"createdAt": "2025-10-01T18:46:41.833Z",
"updatedAt": "2025-10-01T18:46:47.430Z",
"identityType": "BUSINESS",
"paymentRole": "BENEFICIARY",
"internalId": "counterparty-7890",
"business": {
"businessName": "Widgets Org",
"address": {
"streetAddress": ["123 Example MA"],
"country": "US",
"city": "Boston",
"stateOrProvince": "MS",
"postalCode": "12345"
},
"email": "fake@example.com",
"phone": "+1234567890",
"registration": [
{
"number": "123ABC",
"type": "INCORPORATION_CERTIFICATE"
}
],
"incorporationCountry": "US"
}
}Example: Get a specific version
curl -X GET "https://{base-url}/v3/identities/9d839f58-7fd3-4913-a27e-48d31973d3f9?version=1" \
-H "Authorization: Bearer <access_token>"Use versioned lookups when you need to:
- Compare changes over time for audit
- Reconcile payments that used an earlier version of an identity
If the identity or version does not exist, the service returns 404 Not Found.
Use GET /v3/identities to retrieve identities for your tenant with optional filters and pagination.
Supported query parameters:
payment-role– filter by payment role (ORIGINATOR or BENEFICIARY)nick-name– filter by nickname (exact match)limit– maximum number of identities to return (1–100, default 10)next-token– opaque token returned from a previous response, used to fetch the next page
Example: List identities by role
curl -X GET "https://{base-url}/v3/identities?payment-role=BENEFICIARY&limit=2" \
-H "Authorization: Bearer <access_token>"Response (200 OK)
{
"data": [
{
"identityId": "0116bacc-ffbf-4fa2-a29c-ecd9ea346806",
"identityType": "BUSINESS",
"paymentRole": "BENEFICIARY",
"createdAt": "2025-10-01T16:14:13.200Z",
"updatedAt": "2025-10-01T16:14:15.763Z",
"identityState": "ACTIVE",
"nickName": "testNickName",
"tags": ["tag1"],
"version": 2,
"schemaVersion": "1.0.0",
"internalId": "counterparty-7890"
},
{
"identityId": "1d927c62-45fa-4f42-b9f8-8210e1a111bb",
"identityType": "INDIVIDUAL",
"paymentRole": "ORIGINATOR",
"createdAt": "2025-10-01T17:20:05.111Z",
"updatedAt": "2025-10-01T17:20:06.500Z",
"identityState": "ACTIVE",
"nickName": "Alice Originator",
"tags": ["sender", "priority"],
"version": 1,
"schemaVersion": "1.0.0",
"internalId": "customer-12345"
}
],
"nextToken": "eyJrZXkxIjoidmFsdWUifQ=="
}If you receive a nextToken, pass it back as next-token to fetch the next page:
curl -X GET "https://{base-url}/v3/identities?payment-role=BENEFICIARY&limit=2&next-token=eyJrZXkxIjoidmFsdWUifQ==" \
-H "Authorization: Bearer <access_token>"If no identities match your filters, the service returns 404 Not Found.
Use PUT /v3/identities/{identity-id} to update an identity.
The update supports:
- Metadata changes (for example,
nickName,tags) - PII changes (for example,
individualorbusinesscontact details) - Changes to
internalId - Optional re-validation via
validatePayoutRails
Each successful update:
- Creates a new identity version
- Preserves prior versions for audit
- Returns the latest version in the response
When you include internalId in an update request, Identity Management v3 checks whether that value is already assigned to a different ACTIVE identity in your tenant.
- If so, the update fails with 409 Conflict.
- This prevents two ACTIVE identities from sharing the same
internalId.
The request body supports partial updates. Only include the fields you want to change; unspecified fields keep their existing values.
Example: Update nickname and tags
curl -X PUT "https://{base-url}/v3/identities/9d839f58-7fd3-4913-a27e-48d31973d3f9" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"nickName": "Alice Sender USD - Updated",
"tags": ["usd", "high-value"]
}'Response (200 OK) – returns the updated identity (latest version)
{
"identityId": "9d839f58-7fd3-4913-a27e-48d31973d3f9",
"identityState": "ACTIVE",
"nickName": "Alice Sender USD - Updated",
"tags": ["usd", "high-value"],
"version": "3",
"schemaVersion": "1.0.0",
"createdAt": "2025-10-01T18:46:41.833Z",
"updatedAt": "2025-10-02T09:15:10.000Z",
"identityType": "INDIVIDUAL",
"paymentRole": "ORIGINATOR",
"internalId": "customer-12345",
"individual": {
"...": "existing individual details unchanged"
}
}Ellipsis added to keep the example concise; the actual response includes full identity details.
Example: Update internalId
curl -X PUT "https://{pii-base-url}/v3/identities/1d927c62-45fa-4f42-b9f8-8210e1a111bb" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"internalId": "customer-12345-renamed"
}'If customer-12345-renamed is already used by another ACTIVE identity in your tenant, this request fails with 409 Conflict and an error payload describing the conflict.
Example: Update INDIVIDUAL address and validate rails
curl -X PUT "https://{base-url}/v3/identities/1d927c62-45fa-4f42-b9f8-8210e1a111bb" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"validatePayoutRails": ["EU_SEPA", "GB_FPS"],
"individual": {
"address": {
"streetAddress": ["500 Market Street"],
"city": "San Francisco",
"stateOrProvince": "CA",
"postalCode": "94103",
"country": "US"
}
}
}'Example: Update BUSINESS contact info
curl -X PUT "https://{base-url}/v3/identities/0116bacc-ffbf-4fa2-a29c-ecd9ea346806" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"business": {
"email": "ops@example.com",
"phone": "+14155551234"
}
}'If the identity does not exist, the service returns 404 Not Found. If the payload fails validation, it returns 400 Bad Request with field-level error details.
Use DELETE /v3/identities/{identity-id} to deactivate an identity.
Deactivation:
- Sets the identity’s state to DEACTIVATED
- Deactivates the identity’s associated financial instruments
- Prevents any new payments from using this identity
- Keeps historical versions available for audit
Deactivation is permanent; you cannot reactivate a deactivated identity.
Example: Deactivate an identity
curl -X DELETE "https://{base-url}/v3/identities/146f3c51-c313-47ce-b6f2-691c5a238b3e" \
-H "Authorization: Bearer <access_token>"Response (204 No Content) – the identity is successfully deactivated.
Error responses:
- 400 Bad Request – malformed request or invalid
identityIdformat - 404 Not Found – identity does not exist
- 422 Unprocessable Entity – identity is already deactivated or cannot be deactivated (for example, due to internal constraints)
All identity endpoints use a standard error response schema with:
- code – machine-readable error code
- title – short human-readable summary
- description – detailed explanation and remediation hints
Common cases:
- 400 – missing or invalid fields in the request, or identity failing corridor-specific validation rules
- 404 – identity not found (for a specific ID, version, or query)
- 409 –
internalIdconflict (another ACTIVE identity already uses the sameinternalId) - 422 – invalid lifecycle transition (for example, attempting to deactivate an already deactivated identity)
- 500 – internal processing error; retry or contact support if persistent
Refer to the general Error handling section of the API docs for the full list of error codes.
- For a deeper explanation of the identity model, see Payment identities.
- To learn how to attach payout account details to identities (bank accounts, wallets, local payout rails), continue with Create and manage financial instruments.