Beneficiaries
Saved recipients you pay regularly. Idempotent upsert + per-currency rail validation. Soft-deleted beneficiaries are preserved for audit but excluded from active lookups.
The beneficiary object
{
"object": "beneficiary",
"id": "ckben_xxxxxxxxxxxx",
"name": "JANE DOE",
"email": "recipient@example.com",
"phone": "+2348012345678",
"currency": "NGN",
"env": "live",
"bank_code": "044",
"bank_name": "Access Bank",
"account_number": "0690000032",
"account_name": "JANE DOE",
"interac_email": null,
"interac_first_name": null,
"interac_last_name": null,
"verification": "verified",
"is_archived": false,
"is_blacklisted": false,
"source": "manual",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-05-05T12:34:56Z"
}Field notes:
account_nameis the bank-of-record name returned by NUBAN (or the merchant-supplied name for non-resolvable currencies).nameis what the merchant labels them as (often the same).verificationis one ofpending/verified/failed— set when NUBAN resolves successfully.sourceismanualwhen created via API/dashboard,auto_savedwhen created automatically from a successful payout.interac_*fields populate only on CAD beneficiaries; bank-rail fields are null in that case.- FX beneficiaries (GBP / USD / EUR) additionally carry nested
bank+addressblocks and an optionaltype(individual/business) — see the FX shape below.
FX beneficiary object (GBP / USD / EUR)
GBP / USD / EUR rows return the same top-level fields plus nested bank + address blocks and an external_reference:
{
"object": "beneficiary",
"id": "ckben_xxxxxxxxxxxx",
"name": "Jane Doe",
"currency": "USD",
"env": "live",
"type": "individual",
"account_name": "Jane Doe",
"external_reference": "your-ref-123",
"bank": {
"bank_name": "Example Bank",
"method": "ach",
"account_type": "checking",
"routing_number": "021000021",
"sort_code": null,
"iban": null,
"bic_code": null,
"swift_code": null
},
"address": {
"street": "1 Main St",
"city": "New York",
"state": "NY",
"zip_code": "10001"
},
"verification": "verified",
"created_at": "2026-01-15T10:00:00Z",
"updated_at": "2026-05-05T12:34:56Z"
}The bank block only populates the identifiers relevant to the currency (sort_code for GBP, routing_number for USD, iban + bic_code for EUR); the rest are null.
POSTUpsert a beneficiary
Idempotent on the tuple (merchant, currency, env, bank_code, account_number). If a beneficiary already exists for those identifiers:
- The existing row is updated with new name / email / phone (you can correct typos).
- Soft-deleted rows are restored.
- Blacklisted rows refuse update — un-blacklist first.
NGN.
Your label for the recipient. Preserved as your label — the bank-of-record name is captured into account_name automatically.
NUBAN account number.
Bank code (CBN or NIP form).
Bank display name.
Optional metadata.
Optional metadata.
FX currencies use a nested bank + address envelope. country and address.street / address.city / address.zip_code are required for all three; per-currency identifiers differ.
GBP / USD / EUR.
Recipient name.
ISO 3166-1 alpha-2 country code.
individual / business. Required for USD.
street, city, zip_code required for all FX currencies; state additionally required for USD.
Per-currency identifiers: GBP requires bank.account_number + bank.sort_code; USD requires bank.method (ach / wire), bank.account_number, bank.routing_number, bank.account_type (checking / savings), and optional bank.swift_code (used for wire); EUR requires bank.iban + bank.bic_code.
Optional. Your own id, echoed back and usable as a lookup key. Available on any currency.
FX beneficiaries require the international-accounts feature (feature_not_enabled if it’s off). They do not require an active international account in that currency — a beneficiary is a sender-agnostic saved recipient, so whether funds can actually move is decided by the sender at payout time, not at recipient-save time. (Changed 2026-06-08; previously this also required a merchant virtual account.) external_reference is an optional field on any currency — your own id, echoed back and usable as a lookup key.
CAD beneficiaries require all three Interac fields. Bank fields are not used for CAD.
CAD.
Recipient name.
Interac e-Transfer email.
Recipient first name.
Recipient last name.
Identity fields are immutable. You can’t change account_number, bank_code, currency, interac_email, etc. via PATCH. To change the destination account, soft-delete the old beneficiary and create a fresh one.
Idempotency semantics
When a beneficiary already exists for the same (merchant, currency, env, bank_code, account_number) (or (merchant, currency, env, interac_email) for CAD), the response includes a created flag:
| Scenario | created | restored | HTTP |
|---|---|---|---|
| Fresh row | true | (omitted) | 201 |
| Existing active row | false | (omitted) | 200 |
| Restored from archive | false | true | 200 |
| Existing row is blacklisted | refused | refused | 400 beneficiary_blacklisted |
The response is the Beneficiary object extended with the created (and optional restored) flag(s) per the idempotency table above.
{
"currency": "NGN",
"name": "JANE DOE",
"account_number": "0690000032",
"bank_code": "044",
"bank_name": "Access Bank",
"email": "recipient@example.com",
"phone": "+2348012345678"
}curl https://api.swappr.me/api/v1/beneficiaries \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"currency": "NGN",
"name": "JANE DOE",
"account_number": "0690000032",
"bank_code": "044"
}'GETList beneficiaries
Excludes soft-deleted rows by default. To list deleted rows, use the dashboard.
1-100, default 50.
Cursor.
Filter to one currency.
Search by name or account number (case-insensitive contains).
curl 'https://api.swappr.me/api/v1/beneficiaries?currency=NGN' \
-H "Authorization: Bearer sk_test_..."GETRetrieve a beneficiary
Returns the beneficiary including soft-deleted state. For deleted beneficiaries, the deleted_at field is populated and account_number shows the original (un-mangled) value.
curl https://api.swappr.me/api/v1/beneficiaries/ckben_xxxxxxxxxxxx \
-H "Authorization: Bearer sk_test_..."PATCHUpdate a beneficiary
Narrow scope — name, email, phone only. Identity fields immutable.
Recipient label.
Contact email.
Contact phone.
200 OK with updated Beneficiary.
{
"name": "Jane M. Doe",
"email": "recipient.new@example.com",
"phone": "+2348023456789"
}DELSoft-delete a beneficiary
Marks the row deleted but preserves it for audit. The unique-tuple (merchant, currency, env, bank_code, account_number) is freed by mangling the stored account_number; the original is preserved in deleted_account_number for audit + retrieval.
You can re-add the same beneficiary after deletion — that creates a fresh row + leaves the deleted one in history.
Optional reason for the deletion.
200 OK with a beneficiary_delete_result. was_already_deleted is true if you DELETE the same beneficiary twice — the call is idempotent.
{
"reason": "No longer paying this vendor"
}{
"object": "beneficiary_delete_result",
"id": "ckben_xxxxxxxxxxxx",
"deleted": true,
"was_already_deleted": false
}