Skip to content

Create and manage identities

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.

internalId

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.


Before you begin

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:create for creating identities
    • participants:read for reading and listing identities
    • participants:update for 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 real identityId returned by the API

Create an identity

Use POST /v3/identities to create a new identity.

At minimum, you must provide:

  • identityType – INDIVIDUAL or BUSINESS
  • paymentRole – ORIGINATOR or BENEFICIARY
  • Either individual or business details, depending on identityType
  • internalId for 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.

Deduplication via internalId

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 internalId is 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 nickName and tags
  • Add validatePayoutRails to 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"
}
Deduplication via internalId

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"
      }
    }
  }'
Missing or invalid PII

If any required PII is missing or invalid for the rails in validatePayoutRails, the API returns a 400 error describing which fields failed validation.


Get an identity by ID (and version)

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>"
Versioned lookups

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.


List identities

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>"
No identities found

If no identities match your filters, the service returns 404 Not Found.


Update an identity

Use PUT /v3/identities/{identity-id} to update an identity.

The update supports:

  • Metadata changes (for example, nickName, tags)
  • PII changes (for example, individual or business contact 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
Deduplication on update

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.
Partial updates

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"
  }
}
Partial response

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"
  }'
Deduplication on update

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"
    }
  }'
Errors

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.


Deactivate an identity

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
Permanent

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 identityId format
  • 404 Not Found – identity does not exist
  • 422 Unprocessable Entity – identity is already deactivated or cannot be deactivated (for example, due to internal constraints)

Error handling and validation

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)
  • 409internalId conflict (another ACTIVE identity already uses the same internalId)
  • 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.


Next steps