Skip to content

A recipient is the person or company you pay, plus the bank details that reach them in their local currency. SDK methods keep the older name, beneficiary.

  1. Read the corridor’s fields with GET /recipients/{orgId}/corridors.
  2. Register the recipient with POST /recipients/{orgId}.
  3. Store method.destinationAccountId and pay it with Send a payout.
  1. Read the fields before you render a bank-details form:

    GET /recipients/{orgId}/corridors
    x-api-key: avvio_live_…
    {
    "capabilities": { "exactOutput": true, "indicativePricing": true },
    "corridors": [
    {
    "currency": "MXN",
    "fields": [
    { "id": "clabeNumber", "title": "CLABE (18 digits)", "type": "string",
    "required": true, "pattern": "^[0-9]{18}$", "checksum": "clabe" }
    ],
    "limits": { "min": "1.00", "max": "5000.00" }
    }
    ]
    }
    Property What it holds
    currency Always present. Key on this
    fields The bank details to collect. Always id, title, type, required; pattern, checksum, description, options when defined
    limits Floor and ceiling, when the routing publishes them. They change per routing, so don’t hardcode them
    country Only when the routing publishes one (the sandbox doesn’t). Don’t key on it
    settlement Always null; windows, cutoffs and name-matching rules are not published. A payout carries expectedSettlementAt when its network reports one

    checksum names a check the server applies on top of pattern. A value that fails it is refused with 400 VALIDATION_ERROR, and errors[] names the check. Run the same check in your form.

    checksum What it checks
    clabe Digit 18 of a Mexican CLABE checks digits 1-17: weights 3, 7, 1 repeating, each product mod 10 before summing, then (10 - sum mod 10) mod 10 (Banxico’s algorithm; implementations often drop the inner mod)

    The sandbox, never production, accepts the sample 012345678901234567 despite its wrong check digit; test your form with a valid CLABE such as 012180000080004471. Other fields have no rule beyond pattern on our side. A network rejection is also a VALIDATION_ERROR, with the network’s reason in errors[] when it gives one.

  2. POST /recipients/{orgId}
    x-api-key: avvio_live_…
    Idempotency-Key: 7b2e3f81-91a3-481d-91b4-2b13c7a00f2e
    Content-Type: application/json
    {
    "type": "individual",
    "name": "María González",
    "email": "[email protected]",
    "country": "MX",
    "externalId": "emp_42_beneficiary_1",
    "endUserId": "customer_42",
    "method": {
    "kind": "fiat",
    "currency": "MXN",
    "recipientDetails": {
    "clabeNumber": "012180000080004471"
    }
    }
    }
    {
    "id": "cmf3k2xa10004q8b7r5t8u1vw",
    "name": "María González",
    "externalId": "emp_42_beneficiary_1",
    "method": {
    "kind": "fiat",
    "currency": "MXN",
    "last4": "4471",
    "status": "active",
    "destinationAccountId": "sbx_acct_MXN_4471_ae66cbc5"
    }
    }
    Field Required Notes
    type Yes individual or business
    name Yes Non-empty
    method Yes Fiat: kind: "fiat", an ISO 4217 currency, and recipientDetails keyed by the corridor’s field ids. method.rail defaults to the corridor’s rail
    email No A contact address for your records, returned on reads, never used for routing. Stored as null when omitted; must be valid when sent
    country No ISO 3166 alpha-2
    externalId No 1–128 characters, your id for this recipient and account. Not a substitute for Idempotency-Key
    endUserId No 1–128 characters, the party sending through your platform (the employer in payroll), never the person paid. Omit it when you are the sender

    Re-sending an externalId with the same account returns the existing recipient, also with 201, so compare ids to detect a repeat. With a different account it is 409 BENEFICIARY_EXTERNAL_ID_CONFLICT.

    A crypto recipient takes kind: "crypto" and an address. Create accepts EVM, Solana and Bitcoin addresses, but only an EVM (0x…) address can be paid today: a payout to any other address fails with 400 VALIDATION_ERROR. It is paid in USDC on Base from your organization’s wallet, with no fee and sourceAmount equal to destinationAmount. Creating the recipient needs no special scope; paying it needs the crypto_payouts scope on the key, or the payout fails with 400 CRYPTO_PAYOUTS_DISABLED.

  3. You pay method.destinationAccountId, not the recipient id. On a repeat, method is the account the call matched.

Pass endUserId for one end user’s address book, or omit it for the whole organization. limit is 1 to 100 (default 50); pass nextCursor back as cursor.

GET /recipients/{orgId}?endUserId=customer_42&limit=50
x-api-key: avvio_live_…

The response is { scope, recipients, hasMore, nextCursor }, the one list with rows under recipients instead of data. scope echoes the filter. Each row’s id is the recipientId, and paymentMethods[] holds each account’s destinationAccountId.

POST /recipients/{orgId}/{recipientId}/methods
x-api-key: avvio_live_…
Idempotency-Key: <uuid>
Content-Type: application/json
{
"kind": "fiat",
"currency": "EUR",
"recipientDetails": {
"iban": "DE89370400440532013000"
}
}

The response is the whole recipient, with method set to the added account. Accounts match on currency and the corridor’s account fields (for MXN, clabeNumber), not the holder’s name, so sending one again adds nothing. The same account under another recipient is refused with 409 BANK_ACCOUNT_ALREADY_LINKED, carrying existingRecipientId and existingMethodId.

GET /recipients/{orgId}/{recipientId} # our id
GET /recipients/{orgId}/external/{externalId} # your id for them

Lists carry only last4. To show the full account, fetch one method’s details:

GET /recipients/{orgId}/{recipientId}/methods/{methodId}/details
PATCH /recipients/{orgId}/{recipientId}

PATCH changes contact details only: name, email, phone, country and type. A validated bank account can’t be edited; add the correct one as a new method and delete the old one:

DELETE /recipients/{orgId}/{recipientId}/methods/{methodId} # one way of paying them
DELETE /recipients/{orgId}/{recipientId} # the recipient and every method on it

Deleting cancels nothing in flight. The recipient leaves every list, GET answers 404, and a payout to its accounts is refused with 404 DESTINATION_ACCOUNT_NOT_FOUND. Its externalId is released. Deleting a recipient keeps its row (a soft delete); deleting a single method erases that method’s row. Re-adding the same account later works; the new recipient takes over the network’s account id.

Was this page helpful?