The rail decides who verifies the customer
Adding a recipient is gated on the customer’s verification — but on the verification belonging to the provider that onboards that rail, not on one global KYC flag.Required fields are not fixed
There is no single schema that satisfies every recipient. What you must send depends on the currency and the rail together.Ask what this corridor needs
recipientType while you are still creating the recipient.Map each field to the request body
requestPath, the
exact place to send it.Send the seven that are always required
Add the rail-specific coordinates
ifsc for Indian rails, swiftBic for SWIFT, iban for SEPA, sortCode
for UK, bankRoutingNumber for US, walletAddress + walletChain for
CRYPTO.A US bank recipient (bankType: "us") must also carry accountType,
which has to be checking or savings.For Paywho bank transfers, providerBankId: the code of the chosen option on
the bankId field. For GBP, bankBranchCode is filled from sortCode when you
leave it out.Send the country as an id, in two places
countryId — Endl’s numeric id, from
List countries — both at the top
level and inside recipientAddress, alongside the address lines
(addressLine1, addressLine2, city, state, region, postalCode and
country).recipientAddress.countryTwoLetter and countryThreeLetter and they
are used as sent. Leave out either and it is filled from the top-level
countryId; a code you did send is kept.On POBO, also send recipientAddress.countryTwoLetter and
countryThreeLetter; POBO does not derive them.institutionalAddress is the receiving bank’s address, with exactly the same
fields. It is required for GBP, with a valid UK postcode, and is used as the
beneficiary bank address on AED payouts.countryId in two places. Inside recipientAddress it is saved on the
recipient. At the top level it is used to check the payout rail and, if you leave
out recipientAddress.countryTwoLetter or countryThreeLetter, to fill them in;
it is not saved.Verification: immediate for some rails, asynchronous for others
Whether a new recipient is usable straight away depends — again — on the rail.Active immediately
CRYPTO, AED_LOCAL, SWIFT and the Paywho-settled rails create no Bridge
counterparty. The recipient is saved and marked ACTIVE in the same call.
You can pay to it at once.Verified asynchronously
status, counterpartyId, addedToAccountsProvider and statusUpdatedOn.
Statuses you may see: OPEN, ACTIVE, CLOSED, FROZEN, PENDING, EDD,
DORMANT, and the _L2F variants. Treat the set as open and compare
case-insensitively — only ACTIVE means “ready”.
India, IMPS and the penny drop
An India customer adding anIMPS + INR recipient whose
relationshipToCustomer is SELF triggers a penny-drop verification — a
tiny real transfer used to confirm the account exists. It happens inside the add
call: it succeeds and the recipient comes back ACTIVE, or it fails and the add
fails with the provider’s reason.
There is no update
Recipient update was withdrawn from the v0 API. There is noPUT or PATCH
on either the recipients surface or the POBO one.
To change a recipient’s details, add a new recipient and delete the old one.
Transfers already submitted against the old recipient are unaffected — they
carry their own copy of the payout details.
Deleting
Delete is a soft delete. The recipient is marked deleted, stops appearing in listings, and can no longer be referenced — then the external account is removed at the provider asynchronously. The response is200 with a confirmation message, not a recipient object:
404.
Listing
List recipients is aPOST, not
a GET — the filter set is a body, not a query string. size defaults to 0, and
size: 0 returns every recipient rather than none.
Beyond paging (page, size, sortBy — createdOn,desc is recommended) you can
filter on recipientType (INDIVIDUAL, BUSINESS), paymentType
(BANK_ACCOUNT, CRYPTO_WALLET), currency (exact, case-insensitive) and search
(a substring of first name, last name, currency, email or bank name). Other filter
fields are accepted but ignored today.
Each item is the full recipient object.
Keys with no value are left out, except inside the two address objects, and
alias is never returned.
Things that will refuse a recipient
Beyond field validation and the KYC gate, six business rules reject an add:Scoping and reference ids
Every recipients path is/{userId}/…, and both ids in a path are reference
ids, not UUIDs.
404 ERRREF_1001, field userId.
A recipient that is deleted or belongs to a different customer is reported as
404 ERRREC_1000 — Recipient '{recipientId}' not found — never 403. The answer is
the same on Get recipient,
Delete recipient and
Get counterparty checks, so
recipient ids cannot be probed across customers.
A customer that belongs to another partner is reported the same way as one that
does not exist: 404 ERRREF_1001, User with ID '{id}' not found.
Error handling
ERRREC_1000 (404) is the only recipient-domain code: the recipient is deleted or
does not belong to this customer. Everything else uses the shared
envelope and the ERRCORE_ codes in
Errors and the response envelope.
Validation and business refusals come back as 400 with the reason in
errors[0], written to be shown to a user. Branch on errors[0].code, never
on the message text.
Common pitfalls
400 on add, and the message names a field I did not send
400 on add, and the message names a field I did not send
recipientAddress and institutionalAddress an unknown key
is rejected with 400 Invalid value for recipientAddress.<key>. Check the spelling of what you sent — and check
you sent currencySymbol, currencyId and relationshipToCustomer, which
are required on every add.I sent recipientCountry and the country is still missing
I sent recipientCountry and the country is still missing
recipientCountry field. Send countryId at the top level and
inside recipientAddress — the one inside recipientAddress is the country
saved on the recipient.The same customer can add a USDC recipient but gets 403 on a SEPA one
The same customer can add a USDC recipient but gets 403 on a SEPA one
CRYPTO needs Sumsub; SEPA is
Bridge-backed and needs Bridge KYC.My customer has completed Bridge KYC but a SWIFT recipient still returns 403
My customer has completed Bridge KYC but a SWIFT recipient still returns 403
SWIFT is settled by Keyrails, not Bridge, so it asks for Keyrails
onboarding. Bridge KYC does not satisfy it, and completing it would not help: a
SWIFT quote already requires the same Keyrails verification before it will
price, so the recipient would be unusable either way.My recipient was created but a transfer to it fails
My recipient was created but a transfer to it fails
status is ACTIVE.I am waiting for a webhook telling me the recipient is verified
I am waiting for a webhook telling me the recipient is verified
I want to correct a typo in a recipient's account number
I want to correct a typo in a recipient's account number
Supported rails returns 400
Supported rails returns 400
deposit_currency and payout_currency are both mandatory query parameters.
There is no unfiltered listing.List recipients returns nothing
List recipients returns nothing
POST with a body, and size: 0 means every recipient, not none.
Check you are not sending size: 0 expecting an empty page.The recipient was created, but the payout says the bank is missing
The recipient was created, but the payout says the bank is missing
bankId (the Get recipient fields key) or misspelled it.
Send it as providerBankId.My dateOfBirth is rejected as Invalid Date Format
My dateOfBirth is rejected as Invalid Date Format
DD-MM-YYYY, for example 25-01-1994.A UUID in the path returns 400 or 404
A UUID in the path returns 400 or 404
cus_…, recipients are rec_…. A
wrongly-shaped rec_… id is a 400; a well-formed but unknown one is a 404.
A {userId} that doesn’t resolve — a UUID, malformed, unknown or deleted — is
always 404 ERRREF_1001.Glossary
Api-Version: 2026-09.1, from the behaviour of the /api/v0
recipients surface. Rail availability and required fields are configuration and
vary by customer and corridor — read them from
List supported rails and
Get recipient fields
rather than hardcoding this page.