Guide · 05 / 10
Payouts
Move money out with single and bulk disbursements.
A payout moves cleared funds out of one of your wallets to a destination.
Payouts are their own operation class: the key you use must have the payout
scope (payout_only or full) — see Authentication → Scopes.
Amounts are integer minor units. Destinations are always tokenized references
(destination_ref) obtained through the payout-destination tokenization flow —
you never send raw account numbers.
Single payout
POST /payouts — requires an Idempotency-Key.
Request (PayoutCreateRequest):
| Field | Required | Notes |
|---|---|---|
wallet_id | yes | Source wallet (UUID). |
destination_type | yes | mobile_money, bank, or card. |
destination_ref | yes | Tokenized destination reference. |
amount | yes | Minor units, >= 1. |
currency | yes | ISO-4217. |
scheduled_at | no | ISO-8601; schedule the payout for the future. Omit to send now. |
curl -sS https://sandbox.api.wasaapay.com/v1/payouts \
-H "X-WasaaPay-Key: $KEY" -H "X-WasaaPay-Timestamp: $TS" -H "X-WasaaPay-Signature: $SIG" \
-H "Idempotency-Key: 4b1e2d3c-9a8b-4c7d-8e6f-5a4b3c2d1e0f" \
-H "Content-Type: application/json" \
--data '{
"wallet_id": "8f3a2b10-1c9e-4c2a-9b2f-3e6d2a1e9c11",
"destination_type": "mobile_money",
"destination_ref": "tok_dest_9f21ac",
"amount": 500000,
"currency": "KES"
}'
Response (Payout):
{
"data": {
"id": "c9d0e1f2-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
"wallet_id": "8f3a2b10-1c9e-4c2a-9b2f-3e6d2a1e9c11",
"batch_id": null,
"destination_type": "mobile_money",
"destination_ref": "tok_dest_9f21ac",
"amount": 500000,
"currency": "KES",
"status": "queued",
"scheduled_at": null,
"retry_count": 0,
"failure_reason": null,
"created_at": "2026-08-15T09:20:00.000Z"
},
"error": null,
"meta": { "request_id": "req_9f2c1a" }
}
Payout status progresses queued → processing → success / failed, and
each transition emits a payout.* webhook. If the source wallet
can't cover the amount the request fails immediately with 402 INSUFFICIENT_FUNDS.
Read a single payout with GET /payouts/{id}, or list with
GET /payouts?status=&wallet_id= (cursor-paginated).
Bulk payout
Pay many destinations from one wallet in a single call with POST /payouts/bulk.
This creates a payout batch and its individual payouts atomically — ideal for
disbursing to many sub-merchants at once. Requires an Idempotency-Key.
Request (BulkPayoutCreateRequest):
| Field | Notes |
|---|---|
wallet_id | Source wallet shared by every payout in the batch. |
payouts | Array (1–1000). Each item: destination_type, destination_ref, amount, currency. |
curl -sS https://sandbox.api.wasaapay.com/v1/payouts/bulk \
-H "X-WasaaPay-Key: $KEY" -H "X-WasaaPay-Timestamp: $TS" -H "X-WasaaPay-Signature: $SIG" \
-H "Idempotency-Key: a0b1c2d3-e4f5-4061-8273-8495a6b7c8d9" \
-H "Content-Type: application/json" \
--data '{
"wallet_id": "8f3a2b10-1c9e-4c2a-9b2f-3e6d2a1e9c11",
"payouts": [
{ "destination_type": "mobile_money", "destination_ref": "tok_dest_aaa", "amount": 250000, "currency": "KES" },
{ "destination_type": "mobile_money", "destination_ref": "tok_dest_bbb", "amount": 300000, "currency": "KES" }
]
}'
Response (PayoutBatch) reports the batch status (processing,
completed, or partially_failed) and its individual payouts. Poll the batch
with GET /payouts/batches/{id}, or the members with
GET /payouts?wallet_id=....
Wallets
Payouts draw from wallets. List them and check balances (read scope):
curl -sS "https://sandbox.api.wasaapay.com/v1/wallets" \
-H "X-WasaaPay-Key: $KEY" -H "X-WasaaPay-Timestamp: $TS" -H "X-WasaaPay-Signature: $SIG"
curl -sS "https://sandbox.api.wasaapay.com/v1/wallets/{id}/balance" \
-H "X-WasaaPay-Key: $KEY" -H "X-WasaaPay-Timestamp: $TS" -H "X-WasaaPay-Signature: $SIG"
A wallet balance splits into available_balance (spendable now) and
pending_balance (escrowed or uncleared). Only available_balance can be paid
out.
Scheduling with a locked FX rate
For a scheduled cross-currency payout, you can lock a rate ahead of time with
POST /fx/rate-locks (and inspect live rates with
GET /fx/rates?base_currency="e_currency=). A rate lock returns a
locked_rate and an expires_at; use it to protect a future disbursement from
rate movement.