Skip to main content

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:

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.

  1. Call POST /payouts with a full bank set or mobile_money_number + mobile_money_provider (and payout fields) — the same one-of rules as for recipients.
  2. Store the returned payout_uuid and recipient_uuid.
  3. 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).

  1. Register the recipient via POST /payout-recipients and store the recipient_uuid.
  2. Call POST /payouts with the recipient_uuid.
  3. 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:

StatusDescription
pendingThe payout is being processed by the gateway.
successThe payout was successfully sent.
canceledThe 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_uuid nor 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 both mobile_money_number and mobile_money_provider with 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_uuid does 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-statusDescription
pending_createdPayout was just created.
pending_promisePayout is queued or in-flight at the gateway.

Success

Sub-statusDescription
successFunds were successfully transferred.

Canceled

Sub-statusDescription
canceled_failureA technical or unexpected error prevented the payout.
canceled_rejectedThe gateway rejected the payout for a documented reason (e.g. invalid account, insufficient balance).
canceled_timeoutThe payout was not completed within the expected window.