---
updatedAt: 2026-10-16T08:11:00.482Z
---

Fetch the complete documentation index at: https://docs.avvio.xyz/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Create a recipient

`POST https://api.avvio.xyz/business/api/v1/recipients/{orgId}`

Register who is being paid.

`method.recipientDetails` carries the corridor's fields, exactly as
named by `GET /corridors`.

Two separate protections, and they do different jobs:
`Idempotency-Key` makes a *retry* safe; `externalId` makes a *repeat*
safe by returning the existing recipient instead of registering a
second bank account. Send both. The repeat only matches when the
account details are the same: an `externalId` you already used with
a different account is `409 BENEFICIARY_EXTERNAL_ID_CONFLICT`, and a
second account needs a second `externalId`.

A recipient refused by screening is `422 PAYOUT_REFUSED`. The
recipient is still stored, blocked, and every payout to it is refused
the same way; a repeat with the same `externalId` returns it with
`201`. Do not retry the registration.

## Parameters

- `orgId` (path, required) — The opaque organization id issued to you, normally CUID-shaped (for example `cmsx…`). It is not an `org_`-prefixed alias. Pass it unchanged in every organization-scoped path.
- `Idempotency-Key` (header, required) — A unique value per logical operation, 1-255 chars of `A-Z a-z 0-9 _ . : -`. Reuse it to retry. Same key with the same body replays the stored response; same key with a *different* body is a `409`, because answering with the first call's result would hand you a receipt for a payout you did not request. A `4xx` releases the key, so you can fix the body and reuse it. **Reuse it; do not generate one per attempt.** A key minted per attempt defeats replay entirely: every retry looks like a new request, so every retry pays. We also watch for an identical body arriving under a *different* key within 15 minutes and refuse it with `DUPLICATE_REQUEST_DETECTED`. Records are kept for 7 days. That is a retention window only: there is no path where an expired key is re-executed.

## Example

```bash
IDEMPOTENCY_KEY=$(uuidgen)  # new key per call; reuse it only to retry this exact request
curl -s -X POST "$AVVIO_BASE_URL/recipients/$AVVIO_ORG_ID" \
  -H "x-api-key: $AVVIO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "content-type: application/json" \
  -d '{
        "type": "individual",
        "name": "María González",
        "country": "MX",
        "externalId": "cust42_maria",
        "endUserId": "customer_42",
        "method": {
          "kind": "fiat",
          "currency": "MXN",
          "recipientDetails": {
            "clabeNumber": "012180000080004471"
          }
        }
      }'
```

## Responses

- `201` — Created, or the existing recipient for this externalId
- `400` — Validation failed, or a corridor field is missing
- `401` — The key was refused. Nothing ran. - `UNAUTHORIZED`: missing, invalid or revoked, or a key on a route that does not accept one. - `KEY_EXPIRED`: the key passed the expiry it was issued with. Issue a new one; an expired key cannot be rotated. - `KEY_IP_NOT_ALLOWED`: the key is pinned to source addresses and this request came from another.
- `403` — A valid key that may not make this write. Nothing was changed. - `FORBIDDEN`: the key belongs to a different organization. - `ACCOUNT_BLOCKED`: API access for your organization is suspended. - `LIVE_KEY_ORG_NOT_APPROVED`: a live key, before we have approved your business verification. Use a test key until then. - `INSUFFICIENT_SCOPE`: a read-only key. Issue one with the `write` scope.
- `409` — `BANK_ACCOUNT_ALREADY_LINKED`: this bank account is already saved on another recipient (`existingRecipientId`, `existingMethodId`). `BENEFICIARY_EXTERNAL_ID_CONFLICT`: this `externalId` already names a recipient with different account details; nothing was changed. Or an idempotency conflict (`IDEMPOTENCY_KEY_CONFLICT`, `IDEMPOTENCY_KEY_REQUEST_IN_PROGRESS`).
- `422` — `PAYOUT_REFUSED`: this payout cannot be sent to this recipient. Nothing was sent. Do not retry; contact us with the `requestId` if you believe it is wrong. The response never says why.
- `429` — Too many requests. The default ceiling is **100 requests per minute per API credential** on a 60-second window. High-volume payout and reconciliation routes declare a 600/minute override, and batch submission a 30/minute ceiling. A separate 2,000/minute per-source-IP abuse ceiling always applies. Obey `Retry-After`; it is in seconds and is authoritative. A 429 means the request was refused before the handler ran. Retry reads normally; retry an idempotent mutation with its same `Idempotency-Key`.
- `503` — Provider registration is temporarily unavailable; retry safely.

Machine contract: [partner-payouts.openapi.yaml](/partner-payouts.openapi.yaml), operation `createBeneficiary`.
