Skip to main content
A payout sends money out of your Bachs balance to someone else: a supplier, a seller on your platform, a customer being paid out. You register where the money should land once as a destination, then send payouts to that destination by ID. The rail, the payment method, and the account holder name are all derived for you, so a payout request is a destination and an amount. Payouts do not settle synchronously. A successful POST /v1/payouts means the payout was accepted and your balance was reserved, not that the destination has the money. Track the payout to a terminal status before you tell anyone they have been paid.

What Is Supported

The rail is inferred from the destination’s currency, so you do not send a type when you register a destination. Cross-currency payouts (for example, debiting a USD balance to deliver NGN) are available from USD and stablecoin source balances, and require a quote. Call Get Supported Payout Currencies to read live availability rather than hardcoding the table above.
NGN-initiated checkout payments settle to your NGN balance by default. This includes checkouts priced directly in NGN and USD checkouts that resolve to an NGN local price. A USD checkout paid in an NGN equivalent keeps USD settlement behavior. See NGN checkout settlement.

Prerequisites

Before you send your first payout:
  • Authenticate with a valid API key. See Authentication Overview.
  • Confirm your organization is enabled for payouts. Without it, Create Payout returns PAYOUTS_NOT_ENABLED.
  • Fund the balance you are paying from. Check it with Get Balances.
  • For bank destinations, get a valid bank code from List Banks.
  • Register the destination with Create Destination. It is looked up at the bank as part of that call, and an account that resolves comes back approved and ready to pay.
Sandbox payouts are simulated. They move through the same statuses and reach a terminal state on their own, without moving real funds, so you can build the full flow against https://sandbox-api.bachs.io before going live.

How It Works

1

Register the destination

Create the bank account or wallet once with Create Destination, passing the bank code and account number. The account is looked up at the bank during the call, so one that resolves comes back approved and payable. Keep the returned destination ID.An account that cannot be resolved comes back pending_review instead and waits for a human. Read is_usable to tell the two apart.
2

Create a quote, only for a cross-currency payout

If the balance you are paying from is in a different currency from the destination, call Create Payout Quote first. A same-currency payout needs no quote, and quoting one is rejected.
3

Send the payout

Call Create Payout with the destination and an amount, or with a quote_id and no amount for a cross-currency payout.
4

Track it to a terminal status

Subscribe to payout.paid and payout.failed through Webhook Events, or poll Get Payout. List Payouts covers reconciliation across a period.

The Two Things Callers Get Wrong

amount is what the destination receives. The fee is charged on top of it, so a 5000.00 NGN payout with a 100.00 NGN fee debits 5100.00 NGN. Reconcile against total_debited, never against amount. See Create Payout.
A network-level error is not a failed payout. A 500, 502, 503, or 504 tells you the response was lost, not that the money stayed put. Verify the payout’s real state with Get Payout before you retry, and send an Idempotency-Key so a retry cannot pay twice.
Payout statuses are lowercase: pending, processing, completed, failed. Treat pending and processing as non-terminal. Every payouts endpoint (create, retrieve and list) returns them under the same name, status, so a branch written against one endpoint holds on the others.

In This Section

See the API reference for every payouts and payout destinations endpoint.