Payouts
Payouts let you send money to a bank account or a mobile money destination — typically for seller settlements, merchant disbursements, or any third-party transfer.
A payout requires a recipient (a registered bank or mobile money destination) and is always processed through a specific gateway configured for your tenant.
All examples in this guide use mygateway to support local/mock testing.
Workflow
There are two ways to create a payout:
Option A — Inline (recommended for most integrations)
Use the single POST /payouts endpoint and provide the bank or mobile money details directly. Orchestrapay will transparently create or reuse a matching recipient before initiating the payout.
- Call
POST /payoutswith a full bank set ormobile_money_number+mobile_money_provider(and payout fields) — the same one-of rules as for recipients. - Store the returned
payout_uuidandrecipient_uuid. - Listen for payout status updates via webhook.
Option B — Two-step
Useful when you want to pre-register recipients and reuse them across multiple payouts (e.g. recurring merchant settlements).
- Register the recipient via
POST /payout-recipientsand store therecipient_uuid. - Call
POST /payoutswith therecipient_uuid. - Listen for payout status updates via webhook.
Recipient Deduplication
When you use Option A (inline details), Orchestrapay computes a deterministic fingerprint: for bank recipients from the tenant, gateway, bank code, and account number; for mobile money from the tenant, gateway, mobile provider, and mobile_money_number. Submitting the same destination multiple times reuses the same recipient record — no duplicate registrations for an equivalent fingerprint.
Idempotency Keys
You can provide an idempotency_key on both payout and recipient creation requests. Repeating a request with the same key returns the existing resource rather than creating a new one. We strongly recommend using idempotency keys for all payout requests.
Lifecycle
Payouts follow a promise-based model similar to refunds: a payout may not complete synchronously. Possible statuses are:
| Status | Description |
|---|---|
pending | The payout is being processed by the gateway. |
success | The payout was successfully sent. |
canceled | The payout was rejected or failed. |
Each status has a sub-status that provides more detail. See Payout Sub-statuses below.
Webhooks
Provide webhook_urls and an optional webhook_secret on the POST /payouts call. Orchestrapay sends a POST to each URL whenever the payout status changes.
The Orchestrapay-Webhook-Secret header is sent with every call so you can authenticate the request on your side.
See Webhook Payloads for the full payload shape.
Validation Errors
You will receive a 400 Bad Request with a human-readable message if:
- Neither
recipient_uuidnor a valid inline recipient is provided: you must pass either a full bank set (account number, account name, bank code) with no mobile money fields, or bothmobile_money_numberandmobile_money_providerwith no bank account fields. Partial or mixed groups (e.g. two bank fields only, or both a full bank set and a full mobile set) are rejected. - The specified
recipient_uuiddoes not belong to the calling tenant. - The gateway does not support payouts for your tenant or is not enabled.
- The recipient's gateway does not match the requested payout gateway.
Payout Sub-statuses
Pending
| Sub-status | Description |
|---|---|
pending_created | Payout was just created. |
pending_promise | Payout is queued or in-flight at the gateway. |
Success
| Sub-status | Description |
|---|---|
success | Funds were successfully transferred. |
Canceled
| Sub-status | Description |
|---|---|
canceled_failure | A technical or unexpected error prevented the payout. |
canceled_rejected | The gateway rejected the payout for a documented reason (e.g. invalid account, insufficient balance). |
canceled_timeout | The payout was not completed within the expected window. |