Payouts API
The Payouts API lets you send money to a bank account or a mobile money destination. You can provide bank or mobile money details inline (Orchestrapay will create or reuse a recipient automatically) or pass an existing recipient_uuid.
For inline recipients you must send either a complete bank trio (bank_account_number, bank_account_name, bank_code) with no mobile-money fields, or a wallet path with at least mobile_money_number (and no bank account fields). mobile_money_provider is optional when your payout gateway does not require a network label. Do not mix a complete bank set with a mobile money number, and do not send partial bank fields.
Create a payout
Creates a new payout and initiates the transfer with the gateway. If you provide inline bank or mobile money details instead of a recipient_uuid, a recipient is created or reused transparently. The same one-of rules apply as for POST /payout-recipients: a full bank set or mobile money via mobile_money_number (provider optional), not both, and no partial bank fields.
Parameters
amountintegerThe amount to send in cents. E.g. NGN 2,500 → 250000.
currencystringA 3-letter ISO currency code (e.g. NGN).
recipient_uuidoptional, stringUUID of an existing payout recipient. Required if you do not pass a full bank set or a full mobile money set inline.
bank_account_numberoptional, stringBank account number. Required (with the other two bank fields) for inline bank payouts when you omit recipient_uuid and do not use mobile money.
bank_account_nameoptional, stringName on the bank account. Required with the other bank fields for inline bank payouts when not using `recipient_uuid` and not using mobile money.
bank_codeoptional, stringBank code (e.g. "057" for Zenith Bank Nigeria). Required with the other bank fields for inline bank payouts when not using `recipient_uuid` and not using mobile money.
bank_nameoptional, stringHuman-readable bank name. Optional when providing inline bank details.
nameoptional, stringDisplay name for the recipient (used when creating inline).
emailoptional, stringEmail of the recipient (used when creating inline).
phoneoptional, stringPhone number of the recipient (used when creating inline).
mobile_money_numberoptional, stringMSISDN or wallet number for mobile money. Required for inline mobile payouts when you omit `recipient_uuid` and do not use a full bank set (provider below is optional).
mobile_money_provideroptional, stringMobile money network or provider identifier when your gateway expects one. Omit when the gateway only needs the wallet number.
recipient_typeoptional, stringOptional: `bank_account` or `mobile_money`. Inferred if omitted from your bank vs mobile fields.
gatewaystringPayout gateway identifier (e.g. `paystack`, `mygateway`). Must match the recipient's gateway and must be registered for payouts.
tenantoptional, stringTenant name. Defaults to the tenant associated with the API key.
narrationoptional, stringDescription or reason for the transfer, visible on the recipient's bank statement.
idempotency_keyoptional, stringUnique key to prevent duplicate payouts. Repeating a request with the same key returns the existing payout.
webhook_urlsoptional, arrayArray of URLs that receive a POST webhook whenever the payout status changes.
webhook_secretoptional, stringSecret passed as the Orchestrapay-Webhook-Secret header on every webhook call.
metadataoptional, objectArbitrary key-value data you want to attach to the payout for your own reference.
Status Codes
201 Created: Payout was created and submitted to the gateway, or an existing payout was returned for the sameidempotency_key.400 Bad Request: Missing or invalid body (e.g. missinggateway, unknown or non-payout gateway, neitherrecipient_uuidnor a valid inline bank or mobile set, partial bank fields, or both a complete bank set andmobile_money_number), recipient or gateway mismatch, or gateway initiation error.401 Unauthorized: Invalid or missing API key.
curl -X POST https://api.orchestrapay.com/payouts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 250000,
"currency": "NGN",
"gateway": "mygateway",
"narration": "Weekly seller settlement",
"idempotency_key": "settlement-seller-1042-week-15",
"bank_account_number": "0123456789",
"bank_account_name": "JOHN SELLER",
"bank_code": "058",
"bank_name": "Guaranty Trust Bank",
"webhook_urls": ["https://your-domain.com/webhooks/payouts"],
"webhook_secret": "your-webhook-secret"
}'Response Parameters
payout_uuidstringUUID of the payout that was created.
recipient_uuidstringUUID of the recipient used for this payout (created or reused).
statusstringCurrent payout status sub-status (e.g. pending_created, success).
gateway_payout_idstringThe gateway's reference for this transfer, if available immediately.
resource_createdbooleanWhether the payout was newly created (true) or returned from an idempotency key match (false).
{
"payout_uuid": "4c56e5c2-7ef0-4db0-8d2e-5e980f3f3bc7",
"recipient_uuid": "76418b40-8e2d-47c3-ab2f-84e7347d9fcc",
"status": "pending_promise",
"gateway_payout_id": "mock-transfer-301",
"resource_created": true
}Query payouts
Retrieves a paginated list of payouts matching your query criteria. Each payout in data includes the linked recipient relation and tenant_id. The list response does not embed a nested tenant object.
Query Parameters
limitoptional, integer, default is 50Number of results per page (max 1000).
pageoptional, integerPage number to fetch.
sortByoptional, stringSort by property:ASC|DESC (e.g. "created_at:DESC"). Sortable columns: id, created_at, amount.
filteroptional, objectFilter parameters.
Filter Operators
$eqEqual to$notNot equal to$nullIs null$inIn array$gtGreater than$gteGreater than or equal to$ltLess than$lteLess than or equal to$btwBetween$ilikeCase-insensitive like$swStarts with$containsContainscurl https://api.orchestrapay.com/payouts \
-H "Authorization: Bearer YOUR_API_KEY" \
-d "limit=50" \
-d "page=1" \
-d "sortBy=created_at:DESC" \
-d "filter.status=$eq:success" \
-d "filter.currency=$eq:NGN"Get a payout
Returns a single payout by uuid (not numeric database id). The payload includes the recipient relation and tenant_id.
Status Codes
200 OK: Payout found (response body may benullif no matching row).400 Bad Request: Invalid UUID.401 Unauthorized: Invalid or missing API key.
Path Parameters
uuidstring (UUID)The payout's public identifier (returned as `payout_uuid` when you create a payout).
curl https://api.orchestrapay.com/payouts/4c56e5c2-7ef0-4db0-8d2e-5e980f3f3bc7 \
-H "Authorization: Bearer YOUR_API_KEY"Fetch payout status from the gateway
Calls the payout gateway implementation checkPayoutStatus for this payout (for example Paystack transfer verification). This does not update the stored payout row; it returns the gateway's current view of the transfer.
When the API key resolves to a tenant, the payout must belong to that tenant or the API responds with 404 (same as an unknown UUID).
Status Codes
200 OK: Gateway responded; see JSON body (code,response,error_message).400 Bad Request: Missing tenant row for the payout, invalid or blank gateway, or the gateway is not registered for payouts.404 Not Found: Unknown UUID, missing recipient, or payout not visible for this tenant when scoped.401 Unauthorized: Invalid or missing API key.
Path Parameters
uuidstring (UUID)The payout to query at the gateway.
Response fields
codeobjectNormalized response code metadata: `type`, `success`, and numeric `code` (see central response codes).
responseoptional, objectGateway-specific payload (e.g. transfer verification body).
error_messageoptional, stringHuman-readable error from the gateway when `code` indicates failure or pending.
curl https://api.orchestrapay.com/payouts/4c56e5c2-7ef0-4db0-8d2e-5e980f3f3bc7/status \
-H "Authorization: Bearer YOUR_API_KEY"{
"code": {
"type": "ok",
"success": true,
"code": 200
},
"response": { },
"error_message": null
}Payout webhooks
Set webhook_urls and optional webhook_secret on create. Orchestrapay POSTs to every URL when the payout status changes. The request body is JSON; when webhook_secret is set, the value is sent in the Orchestrapay-Webhook-Secret header.
Deliveries include at least:
pending_created— immediately after the payout is persisted, before gateway initiation completes.- A follow-up after initiation — typically
pending_promise(still processing),success,canceled_rejected, orcanceled_failure, depending on the gateway outcome.
Each event includes webhook_type: "payout", uuid, status (pending, success, or canceled), sub_status (full value such as pending_promise), amount, currency, gateway references, and optional failure_reason on failures.
See Payout Webhook for the full field list and example JSON.
Payout Statuses
Payouts have three main statuses:
pending: The payout is being processed by the gateway.success: Funds were successfully transferred.canceled: The payout failed or was rejected.
Sub-statuses
pending_created: Payout record was just created.pending_promise: Transfer is in-flight at the gateway.success: Transfer completed successfully.canceled_failure: An unexpected technical error occurred.canceled_rejected: The gateway rejected the transfer (e.g. invalid account, insufficient balance).canceled_timeout: The payout did not complete within the expected window.