Sender and recipient user APIs

User creation is now split by the role the user plays in an order. Previously a single
pair of user creation APIs served every order type; you now create a sender (the
party funding an order) or a recipient (the party being paid), and a user can hold
both roles at once.

This release adds the sender APIs, documents the recipient APIs in full, adds a role
change flow for granting an existing user a second role, and adds new ways to read back
which roles a user holds and how far each role has cleared verification.

The current user creation apis of POST /v3/users/individual and
POST /v3/users/business will be deprecated.


New user creation APIs

Senders

A sender is the party that funds an order. New Senders tag.

EndpointDescription
POST /v3/senders/mandatory-fieldsReturns the fields required to create a sender for a given country, sender type and currency type, plus the validation rules applied to them.
POST /v3/senders/individualCreates an individual sender and returns the userId used for KYC and for every order they pay for.
POST /v3/senders/businessCreates a business sender — a legal entity that funds orders — and returns the userId used for KYB and for every order it pays for.

Call mandatory-fields first with type: individual or type: organization, then build
the creation body from the inputs it returns. The field set varies by corridor, so the
properties shown in the reference are one corridor's fields, not a fixed list. The
request body also accepts nested field groups, so a corridor that returns something
like address: { state, city, postalCode } can be submitted as-is.

mandatory-fields also returns a rules array describing cross-field constraints — see
Cross-field validation rules.

Submitting details that match an existing sender returns 200 with the existing userId
and code: USER_ALREADY_EXISTS.

There is no fiat/crypto distinction for senders — a sender is a sender regardless of
how the order is funded.

Recipients

A recipient is the party being paid. These endpoints already existed but were lightly
used, so they are documented here in full alongside the senders they mirror.

EndpointDescription
POST /v3/recipients/mandatory-fieldsReturns the fields required to create a recipient for a given country, recipient type and currency type, plus the validation rules applied to them.
POST /v3/recipients/individualCreates an individual recipient and returns the userId you reference when paying them.
POST /v3/recipients/businessCreates a business recipient — a legal entity that receives payouts — and returns the userId you reference when paying it.

The flow is identical to senders: fetch mandatory-fields, build the body from inputs,
submit. Matching details return the existing userId with code: USER_ALREADY_EXISTS.

Unlike senders, recipients are distinguished by payout rail. A recipient paid to a
crypto wallet and a recipient paid to a bank account are different roles —
RECIPIENT_CRYPTO and RECIPIENT_FIAT — and one user can hold both. To add the second
rail to a recipient you already created, use the role change flow.

Changes to the existing recipient endpoints in this release:

  • POST /v3/recipients/mandatory-fields: geo and currencyType are now optional.
    type is the only required field.
  • POST /v3/recipients/mandatory-fields: the rules array is now documented — it was
    always returned, matching the senders endpoint. See
    Cross-field validation rules.
  • POST /v3/recipients/business: countryOfIncorporation has been removed from the
    request — it duplicated country.
  • Both creation endpoints now accept nested field groups in the request body.

Role change

Grants an existing user an additional role, so a user created as a recipient can also
fund orders, or a user created as a sender can also be paid out. The user is not
re-onboarded and keeps the same userId; the new role is added to the roles they already
hold. New Role Change tag.

EndpointDescription
POST /v3/role-change/mandatory-fieldsStep 1. Returns the additional data TransFi needs before the user can also act in targetRole.
POST /v3/role-change/individualStep 2, for users created as individuals.
POST /v3/role-change/businessStep 2, for users created as organizations.

All three take userId and targetRole (sender or recipient). Step 1 may return
nothing further to collect, in which case step 2 can be called with just those two
fields.

Use it when an existing sender needs to receive payouts, or an existing recipient
needs to fund orders. Only users created through the sender or recipient creation APIs
are supported; others return 400 USER_VERSION_MISMATCH.

Changing a recipient's payout rail. Switching rails between fiat and crypto currencyType is also a role change: to pay an existing crypto recipient in fiat, call the role change endpoints with targetRole: recipient and currencyType: fiat. Step 1 returns the fiat payout details still to be collected, and
submitting them in step 2 adds the fiat rail. Use currencyType: crypto for the reverse.

currencyType accepts fiat or crypto and defaults to fiat when omitted, so send
it explicitly whenever the target rail is crypto.

Cross-field validation rules

All three mandatory-fields endpoints — senders, recipients and role change — return a
rules array alongside the field list. A rule constrains a group of fields together,
on top of the per-field validation described in inputs:

typeMeaning
either_requiredAt least one of the listed fields must be supplied.
mutually_requiredThe listed fields must be supplied together — all of them, or none.

Each rule carries the fields it applies to and a validationMessage to surface when it
fails. These two types are the complete set. The array is always present, and empty for a
corridor with no cross-field constraints.

"rules": [
  {
    "type": "either_required",
    "fields": ["email", "phone"],
    "validationMessage": "Either email or phone number is required."
  },
  {
    "type": "mutually_required",
    "fields": ["phone", "phoneCode"],
    "validationMessage": "Phone number and phone code must be provided together"
  }
]

Check the rules before submitting: a field shown as isMandatory: false in inputs can
still be required by an either_required rule, so the per-field flags alone are not
enough to validate a payload.


Reading sender and recipient data

List individual users / list business users

GET /v3/users/individual and GET /v3/users/business gain a way to find users by the
role they hold.

New accountType request parameter. Optional query filter, one of sender,
recipient_fiat or recipient_crypto (lowercase). sender returns sender accounts;
recipient_fiat and recipient_crypto return users holding at least one fiat or crypto
payout account identifier respectively. Combines with the existing email, phone and
name filters.

New accountType response field. Each user in the list now carries the roles they
hold, as an array:

"accountType": ["SENDER", "RECIPIENT_FIAT"]

Values are SENDER, RECIPIENT_FIAT and RECIPIENT_CRYPTO. The field is omitted when
the user holds no roles yet.

New accountIdentifier response field. The payout account identifiers attached to
the user, each with a type (bank_account, iban, e_wallet, mobile_wallet,
crypto_wallet_address) and a value. Present for users holding a recipient role — this
is what the recipient roles above are derived from.

Get account type

EndpointDescription
GET /v3/users/account-typeReturns the roles held by a single individual or business user.

Takes userId. Returns the same role array as the list endpoints:

{
  "status": "success",
  "data": {
    "id": "UX-260415082930591603",
    "entityType": "USER",
    "accountType": ["SENDER", "RECIPIENT_FIAT"]
  },
  "traceId": "2c8d0e5f-3b16-4a79-9d24-7e1f6a0b3c58"
}

Useful for confirming a role change took effect before you rely on the new role. Only
supported for users created through the sender or recipient creation APIs; others return
400 USER_VERSION_MISMATCH.

Get account status

GET /v3/kyc/status/USERID and GET /v3/kyb/status/USERID return one account-wide
verdict. Because a user can now hold two roles that clear verification independently,
these endpoints break that verdict down per role.

EndpointDescription
GET /v3/kyc/account-statusKYC tiers for an individual user, split into sender and recipient blocks.
GET /v3/kyb/account-statusKYB tiers for a business user, split into sender and recipient blocks.

Both take userId (required) and an optional accountType (sender, recipient or
both). A role's kyc / kyb block is null when the user holds no verification
record for that role — the role key is still present.

{
  "status": "success",
  "data": {
    "userId": "UX-260715173645137430",
    "accountType": "both",
    "sender":    { "kyc": { "basicKycStatus": "approved", "standardKycStatus": "not_applicable", "advancedKycStatus": "not_applicable" } },
    "recipient": { "kyc": null }
  },
  "traceId": "7b1e5d92-64af-4c03-9e28-af5b0c31d7e4"
}

Use these to check that the specific role you are about to transact with has cleared,
rather than the account as a whole.


Using senders and recipients with orders

POST /v3/orders is unchanged. What changes is which user you create for the
userId you pass to it.

Order typeUser to create
payoutRecipient — the party being paid
onramp, offramp, payin, swap, gamingSender — the party funding the order

Previously a single user creation API covered every order type. Existing integrations
using POST /v3/users/individual and POST /v3/users/business are unaffected.

For the user-user (third-party) offramp flow, the root-level userId is omitted and
source.userId and destination.userId are supplied instead — the source is the sender
and the destination is the recipient.

Because recipients are split by payout rail, create the recipient against the rail you
intend to pay them on: a recipient with a crypto wallet identifier is a
RECIPIENT_CRYPTO, and one with a bank, IBAN or wallet identifier is a RECIPIENT_FIAT.
Senders carry no such distinction.