Chapa

Payout

Send money from your Chapa balance to bank accounts or mobile money wallets.

Payouts allow you to send money from your Chapa balance to a bank account or mobile money wallet.

This feature is commonly used for:

  • Vendor payouts
  • Customer withdrawals
  • Partner settlements
  • Internal fund disbursement

Payouts are asynchronous. A successful API response means the payout was created, not completed.

Endpoint

POST /v2/payouts
Host: api.chapa.global

Authentication

Headers

NameRequiredDescription
AuthorizationYesBearer <PRIVATE_API_KEY>
Content-TypeYesapplication/json
Idempotency-KeyNoPrevents duplicate payout creation on retries

Request Body

Required Fields

FieldTypeDescription
amountnumberAmount to transfer
currencystringISO currency code (USD, UGX, ETB, DJF, availability depends on payout method)
accountobjectDestination account details

Optional Fields

FieldTypeDescription
merchant_referencestringMerchant-generated payout reference (optional)
reasonstringDescription of the payout
metaobjectCustom metadata for internal tracking

Account Object

FieldDescription
account_nameName on the receiving account
account_numberBank account or wallet identifier
bank_slugShort bank or wallet identifier
bank_nameDisplay name of the bank or wallet

Example Request

Example Request
JSON
{
  "amount": 500,
  "currency": "ETB",
  "account": {
    "account_number": "0926760003",
    "account_name": "Abebe Bikila",
    "bank_slug": "yaya",
    "bank_name": "yaya"
  },
  "reason": "Vendor payout for services",
  "meta": {
    "a": "b"
  }
}
cURL
curl -X POST https://api.chapa.global/v2/payouts \
  -H "Authorization: Bearer CHAPA_TEST_xxxxxxxxxxxxx"
  -H "Content-Type: application/json" \
  -d '{
  "amount": 500,
  "currency": "ETB",
  "account": {
    "account_number": "0926760003",
    "account_name": "Abebe Bikila",
    "bank_slug": "yaya",
    "bank_name": "yaya"
  },
  "reason": "Vendor payout for services",
  "meta": {
    "a": "b"
  }
}'
JavaScript
const response = await fetch("https://api.chapa.global/v2/payouts", {
  method: "POST",
  headers: {
    "Authorization": "Bearer CHAPA_TEST_xxxxxxxxxxxxx",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "amount": 500,
  "currency": "ETB",
  "account": {
    "account_number": "0926760003",
    "account_name": "Abebe Bikila",
    "bank_slug": "yaya",
    "bank_name": "yaya"
  },
  "reason": "Vendor payout for services",
  "meta": {
    "a": "b"
  }
})
});
const data = await response.json();

console.log(data);

Example Response

Example Response
Success
{
  "status": "success",
  "message": "Payout initialized successfully",
  "data": {
    "chapa_reference": "CP123456789",
    "status": "pending"
  },
  "created_at": "2025-11-07T11:06:00Z",
  "updated_at": "2025-11-08T11:06:00Z"
}

At this stage, the payout is pending, not completed.

Payout Status Lifecycle

A payout may move through the following states:

StatusMeaning
pendingCreated but not yet processed
processingBeing processed
success / completedFunds delivered successfully
failedPayout failed
blockedBlocked due to risk or compliance
auth_neededAdditional authorization required
otp_neededOTP verification required
reversedFunds reversed after processing

Status changes are delivered via webhooks and can be checked via verification.

Verification (Optional)

To check the current status of a payout:

GET /v2/payouts/{reference}/verify

Verification is useful for:

  • Payout confirmation
  • Reconciliation
  • Customer support inquiries
  • Dispute resolution

Payout lifecycle events are sent via webhooks:

  • payout.success
  • payout.failed
  • payout.reversed
  • payout.blocked
  • payout.auth_needed
  • payout.otp_needed

Your system should:

  • Update payout state idempotently
  • Store chapa_reference and merchant_reference
  • Log reasons and timestamps
  • Avoid duplicate processing

Best Practices

  • Always generate a unique merchant_reference
  • Use Idempotency-Key when retrying payout requests
  • Validate bank and account details before initiating
  • Handle payout status asynchronously via webhooks
  • Never assume success immediately after initialization

Common Errors

HTTPError CodeDescription
400INVALID_FORMATInvalid bank slug or account number
404NOT_FOUNDPayout not found
500PROCESSING_FAILEDFailed to create payout

Next Steps

On this page