API referencePayoutsOverview

Payouts

Send money to recipients across NGN bank accounts, CAD Interac email IDs or EFT bank accounts, 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.

CurrencyPageHow it routes
NGNNGN payoutsNigerian interbank rails (NIP), multi-provider cascade
GBPGBP payoutsInternational account rail (Faster Payments), backed by your GBP virtual account
USDUSD payoutsInternational account rail (ACH or wire), backed by your USD virtual account
EUREUR payoutsInternational account rail (SEPA), backed by your EUR virtual account
CADCAD payoutsTwo rails — Interac e-Transfer (email-routed) or EFT (Canadian bank account), selected per payout with method

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). If your account is configured for both flows, the gate follows the payout — see sender attribution. This gate applies to GBP, USD and EUR only, so CAD is exempt on both the Interac and EFT rails. NGN works out of the box. Which requirements apply depends on how Technest has configured your account for that currency — ask us if you’re unsure which applies to you.

Two ways to specify the recipient

  1. beneficiary_id — reference a recipient you saved via POST /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.
  2. Inline recipient — pass the recipient details on the payout itself. Standard for NGN. Still supported for FX, but soft-deprecated.

When beneficiary_id is set, any inline recipient is ignored.

Common fields (all currencies)

FieldTypeRequiredNotes
amount_minorstring (BigInt)yesMinor units — kobo for NGN, cents for USD/EUR, pence for GBP, cents for CAD. Never a float.
currencystringyesNGN | GBP | USD | EUR | CAD
recipientobjectconditionalInline recipient (currency-specific). Required unless beneficiary_id is supplied.
beneficiary_idstringconditionalSaved beneficiary reference. Alternative to recipient. Must match the payout currency.
wallet_idstringnoAuto-resolved from currency + env if omitted.
merchant_referencestringnoYour own ref. Unique per merchant in a 30-day window.
narrationstringnoDescription shown on the recipient’s statement (NGN).
customer_idstringnoSender attribution — your end-user customer id (see Customers). Surfaces in payout.* webhooks, GET responses, and the customer’s transaction history.
customer_referencestringnoOpaque attribution string (max 64 chars), echoed in webhooks + GETs.
sender_customer_idstringconditionalFX sender id — required on CAD / GBP / USD / EUR in the individual flow (an inline sender block does not substitute); omit it in the business/treasury flow; optional, and it selects the flow per payout, if your account is configured for both. See sender attribution.
senderobjectconditionalInline sender identity for compliance. See sender attribution.
allow_duplicatebooleannoBypass 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. Keys are scoped per merchant, per environment — a key used in sandbox is free to reuse in live, where it creates a real payout. Keys do not expire. See Idempotency.

Key capability required

The API key must be enabled for payout creation. Tick Create payouts on the key in API keys, or the request returns:

{
  "error": {
    "type": "permission_error",
    "code": "permission_denied",
    "message": "This API key isn't enabled for creating payouts. Enable payout.create on the key in API keys."
  }
}

The capability is set per key, so you can hold a read-only key and a payout-enabled key on the same account. Enabling it requires the payout.create permission — a teammate without it can create the key, but someone with it must switch the capability on. Turning it off needs no permission.

Cross-currency payouts require both this capability and payout.fx on the key — see Cross-currency payouts.

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. How you supply the sender depends on your flow.

Individual flow — send sender_customer_id on every payout, referencing a customer you created via POST /v1/customers. It is required: an inline sender block does not substitute for it, and omitting it returns missing_field. Swappr resolves that customer’s stored KYC to satisfy the sender-info requirement and uses it for attribution.

Business / treasury flow — omit sender_customer_id. The sender is your merchant treasury customer, resolved automatically. If only this flow is enabled on your account, sending one anyway returns customer_id_mismatch.

Both flows enabled — if Technest has enabled both flows on your account, sender_customer_id is optional, and it selects the flow per payout. Supply it and the payout is attributed to that end customer and leaves the sender’s own account (sender_account_not_provisioned if they have none). Omit it and the payout is attributed to your treasury customer and leaves your merchant international account (no_active_international_account if you have none). customer_id_mismatch does not apply — supplying a sender is a valid instruction for this configuration, not an error. This is a Technest-configured capability, not a per-request option.

The sender block carries the sender’s identity inline (name, ID type/number, date of birth, country). It is how a business/treasury account supplies identity when its account is configured to require sender info, and it may also accompany sender_customer_id in the individual flow — the two are complementary: inline sender fields take precedence per-field and the referenced customer’s stored KYC backfills any 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

CodeHTTPCause
missing_field400Required body field absent
invalid_field422Wrong type / format
wallet_not_found422wallet_id doesn’t match merchant + currency + env
unsupported_currency422Currency not active for this merchant
beneficiary_not_found404beneficiary_id unknown / not yours / wrong env
beneficiary_currency_mismatch400beneficiary_id currency ≠ payout currency
fx_features_not_enabled403International accounts not enabled for this merchant (FX currencies)
no_active_international_account403(Business/treasury flow) No active merchant international account for this currency
sender_account_not_provisioned422(Individual flow) The sending customer has no active virtual account in this currency — issue one via POST /v1/customers/{id}/virtual_accounts
customer_not_found404customer_id unknown / not yours
customer_id_mismatch400customer_idsender_customer_id on an FX payout — or a business/treasury-only account sent a per-payout sender_customer_id (omit it; the sender is your treasury customer). The second cause does not apply to an account configured for both flows
no_treasury_customer400(Business/treasury flow) Your treasury customer isn’t provisioned yet — contact Technest to set up your international payouts
env_mismatch409customer_id belongs to the other environment
sender_info_required422Your account is configured to require sender identity and the merged sender details (inline sender block + the referenced customer’s stored KYC) are still incomplete
idempotency_key_conflict409Same Idempotency-Key, different body
provider_error502Downstream 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/v1

Manage 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 the po_… reference).
  • POST /v1/payouts/{id}/requery — force a provider status refresh for a stuck processing payout.
  • POST /v1/payouts/{id}/cancel — cancel a draft or queued payout.

See any per-currency page for the full payout object, status values, and the management-endpoint details.