Payouts
Send money to recipients across NGN bank accounts, CAD Interac email IDs, and GBP / USD / EUR bank rails — one endpoint, POST /v1/payouts, with a currency-specific recipient block.
Each currency has its own integration page. A page is self-contained: if you only send GBP, you only need the GBP page.
| Currency | Page | How it routes |
|---|---|---|
| NGN | NGN payouts | Nigerian interbank rails (NIP), multi-provider cascade |
| GBP | GBP payouts | International account rail (Faster Payments), backed by your GBP virtual account |
| USD | USD payouts | International account rail (ACH or wire), backed by your USD virtual account |
| EUR | EUR payouts | International account rail (SEPA), backed by your EUR virtual account |
| CAD | CAD payouts | Interac e-Transfer (email-routed — no bank account needed) |
GBP / USD / EUR / CAD require international accounts to be enabled on your account. The GBP/USD/EUR send gate then depends on your flow (individual vs business): an individual sends from the sender’s own virtual account (sender_account_not_provisioned if missing), a business/treasury merchant sends from its own international account (no_active_international_account if missing). CAD routes via Interac for both. NGN works out of the box.
Two ways to specify the recipient
beneficiary_id— reference a recipient you saved viaPOST /v1/beneficiaries. Swappr resolves the full recipient details server-side. Preferred for FX (GBP / USD / EUR / CAD): the saved beneficiary captures the address details the receiving network needs, so payouts settle reliably.- Inline
recipient— pass the recipient details on the payout itself. Standard for NGN. Still supported for FX, but soft-deprecated — preferbeneficiary_idfor new FX integrations.
When beneficiary_id is set, any inline recipient is ignored.
Common fields (all currencies)
| Field | Type | Required | Notes |
|---|---|---|---|
amount_minor | string (BigInt) | yes | Minor units — kobo for NGN, cents for USD/EUR, pence for GBP, cents for CAD. Never a float. |
currency | string | yes | NGN | GBP | USD | EUR | CAD |
recipient | object | conditional | Inline recipient (currency-specific). Required unless beneficiary_id is supplied. |
beneficiary_id | string | conditional | Saved beneficiary reference. Alternative to recipient. Must match the payout currency. |
wallet_id | string | no | Auto-resolved from currency + env if omitted. |
merchant_reference | string | no | Your own ref. Unique per merchant in a 30-day window. |
narration | string | no | Description shown on the recipient’s statement (NGN). |
customer_id | string | no | Sender attribution — your end-user customer id (see Customers). Surfaces in payout.* webhooks, GET responses, and the customer’s transaction history. |
customer_reference | string | no | Opaque attribution string (max 64 chars), echoed in webhooks + GETs. |
sender_customer_id | string | conditional | FX sender id — required for CAD / GBP / USD / EUR unless a full inline sender block is supplied. See sender attribution. |
sender | object | conditional | Inline sender identity for compliance. See sender attribution. |
allow_duplicate | boolean | no | Bypass the beneficiary cool-down for an intentional retry. |
The Idempotency-Key header is required on POST /v1/payouts. Same key + same body returns the cached response; same key + different body returns 409.
Customer attribution
customer_id + customer_reference link a payout to one of your end-user customers. Once set, the values appear in payout.* webhooks, the payout’s GET response, and the unified GET /v1/customers/{id}/transactions feed — so you can rebuild a customer’s history without storing every event yourself. Both are optional and work on every currency.
Sender attribution (FX)
For FX currencies (CAD / GBP / USD / EUR) the sending customer must be identified for compliance. You can do this two ways, and they are complementary, not mutually exclusive:
sender_customer_id— reference a customer you created viaPOST /v1/customers. Swappr resolves their stored KYC to satisfy the sender-info requirement, and uses it for attribution.senderblock — the sender’s identity inline (name, ID type/number, date of birth, country).
If you pass both, the inline sender fields take precedence per-field and the referenced customer’s stored KYC backfills any fields you omit. If you pass customer_id as well, it must match sender_customer_id (both reference the sending customer) or the request is rejected with customer_id_mismatch.
Common error codes
| Code | HTTP | Cause |
|---|---|---|
missing_field | 400 | Required body field absent |
invalid_field | 422 | Wrong type / format |
wallet_not_found | 422 | wallet_id doesn’t match merchant + currency + env |
unsupported_currency | 422 | Currency not active for this merchant |
beneficiary_not_found | 404 | beneficiary_id unknown / not yours / wrong env |
beneficiary_currency_mismatch | 400 | beneficiary_id currency ≠ payout currency |
fx_features_not_enabled | 403 | International accounts not enabled for this merchant (FX currencies) |
no_active_international_account | 403 | (Business/treasury flow) No active merchant international account for this currency |
sender_account_not_provisioned | 422 | (Individual flow) The sending customer has no active virtual account in this currency — issue one via POST /v1/customers/{id}/virtual_accounts |
customer_not_found | 404 | customer_id unknown / not yours |
customer_id_mismatch | 400 | customer_id ≠ sender_customer_id on an FX payout |
env_mismatch | 409 | customer_id belongs to the other environment |
sender_info_required | 422 | Account requires sender info; supply sender or sender_customer_id |
idempotency_key_conflict | 409 | Same Idempotency-Key, different body |
provider_error | 502 | Downstream rail unreachable; safe to retry with the same key |
Per-currency pages list the extra codes specific to each rail.
Base URL
All examples use the production base URL — the environment is selected by your secret-key prefix (sk_test_… vs sk_live_…):
https://api.swappr.me/api/v1Manage payouts
POST /v1/payouts creation is documented per currency. The management endpoints below are currency-agnostic:
GET /v1/payouts— list (cursor-paginated; filter by status / currency / date).GET /v1/payouts/{id}— retrieve (accepts the cuid or thepo_…reference).POST /v1/payouts/{id}/requery— force a provider status refresh for a stuckprocessingpayout.POST /v1/payouts/{id}/cancel— cancel adraftorqueuedpayout.
See any per-currency page for the full payout object, status values, and the management-endpoint details.