Payouts
This guide explains how to implement payouts, verify transaction status, and handle webhook notifications. Payouts allow you to send funds to recipients through mobile money, bank accounts, and other local payment methods.
1 - Initiate Mobile Money Payout
To send funds to a mobile money wallet, collect the required recipient information and send it to the payouts endpoint.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | Number | ✅ | Amount to payout (e.g. 1000) |
| currency | String | ✅ | Currency code (e.g. KES, UGX, NGN) |
| country | String | ✅ | ISO 3166-1 alpha-2 country code (e.g. KE, UG) |
| externalReference | String | ✅ | Your own unique ID for reconciliation (e.g. payout_12345) |
| payoutMethod | Object | ✅ | Recipient details (see below) |
| destination | String | ✅ | Set to MoMo for mobile money |
| debitCurrency | String | ❌ | Wallet currency to debit from (if different from payout currency) |
Payout Method Object (Mobile Money):
| Field | Type | Required | Description |
|---|---|---|---|
| accountName | String | ✅ | Recipient name |
| accountNumber | String | ✅ | Phone number with country code, no plus sign (e.g. 254719624552) |
| code | String | ❌ | Mobile money operator ID (required for some currencies) |
Example Request:
{
"amount": 1000,
"currency": "KES",
"country": "KE",
"externalReference": "payout_seller_001",
"payoutMethod": {
"accountName": "John Doe",
"accountNumber": "254719624552",
"code": "MPESA"
},
"destination": "MoMo"
}
Below is an example of the response:
Success
{
"success": true,
"message": "Payout initiated successfully.",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"amount": 1000,
"currency": "KES",
"externalReference": "payout_seller_001"
}
}
Note: Use the returned transactionId (or your externalReference) to track the payout status. Mobile money payouts are processed asynchronously.
2 - Initiate Bank Account Payout
To send funds to a bank account, use the same endpoint with bank-specific details.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | Number | ✅ | Amount to payout |
| currency | String | ✅ | Currency code |
| country | String | ✅ | ISO 3166-1 alpha-2 country code |
| externalReference | String | ✅ | Your own unique ID for reconciliation |
| payoutMethod | Object | ✅ | Recipient bank details (see below) |
| destination | String | ✅ | Set to Bank Account |
Payout Method Object (Bank Account):
| Field | Type | Required | Description |
|---|---|---|---|
| accountName | String | ✅ | Account holder name |
| accountNumber | String | ✅ | Bank account number |
| code | String | ✅ | Bank code (retrieve from Get Banks API) |
To retrieve the correct bank code, use the Get Banks API:
Plain Text
GET /api/b2b/utilities/banks?country=KE
Example Request:
{
"amount": 50000,
"currency": "KES",
"country": "KE",
"externalReference": "payout_vendor_bank_001",
"payoutMethod": {
"accountName": "ABC Company Ltd",
"accountNumber": "1234567890",
"code": "1243"
},
"destination": "Bank Account"
}
Example Response:
{
"success": true,
"message": "Payout initiated successfully.",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"amount": 50000,
"currency": "KES",
"externalReference": "payout_vendor_bank_001"
}
}
Note: Bank payouts may take longer to process than mobile money payouts. Processing times vary by bank and country.
3 - Initiate M-Pesa Paybill Payout (Kenya Only)
To send funds to an M-Pesa Paybill account (Kenya only), use the paybill destination.
Payout Method Object (Paybill):
| Field | Type | Required | Description |
|---|---|---|---|
| accountName | String | ✅ | Recipient name |
| accountNumber | String | ✅ | Paybill account number |
| businessNumber | String | ✅ | Paybill business number |
Example Request:
{
"amount": 5000,
"currency": "KES",
"country": "KE",
"externalReference": "payout_paybill_001",
"payoutMethod": {
"accountName": "John Doe",
"accountNumber": "1234567890",
"businessNumber": "123456"
},
"destination": "Paybill"
}
Example Response:
{
"success": true,
"message": "Payout initiated successfully.",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"amount": 5000,
"currency": "KES",
"externalReference": "payout_paybill_001"
}
}
4 - Initiate M-Pesa Till Payout (Kenya Only)
To send funds to an M-Pesa Till account (Kenya only), use the till destination.
Payout Method Object (Till):
| Field | Type | Required | Description |
|---|---|---|---|
| accountName | String | ✅ | Recipient name |
| accountNumber | String | ✅ | Till number |
Example Request:
{
"amount": 2500,
"currency": "KES",
"country": "KE",
"externalReference": "payout_till_001",
"payoutMethod": {
"accountName": "John Doe",
"accountNumber": "123456"
},
"destination": "Till"
}
Example Response:
{
"success": true,
"message": "Payout initiated successfully.",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"amount": 2500,
"currency": "KES",
"externalReference": "payout_till_001"
}
}
5 - Payout Using External Account
If you have previously created an external account for a recipient, you can initiate payouts using just the externalAccountId without re-entering recipient details.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | Number | ✅ | Amount to payout |
| externalReference | String | ✅ | Your own unique ID for reconciliation |
| externalAccountId | String | ✅ | ID of the saved external account |
Example Request:
{
"amount": 1000,
"externalReference": "payout_recurring_001",
"externalAccountId": "zxEFheZW6DlnCgXJIJDz"
}
Example Response:
{
"success": true,
"message": "Payout initiated successfully.",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"amount": 1000,
"externalReference": "payout_recurring_001"
}
}
For more information on creating and managing external accounts, see the Create an External Account documentation.
6 - Multi-Currency Payouts
You can initiate payouts in a recipient's local currency while debiting from a different wallet currency. Use the debitCurrency parameter to specify the wallet to debit from.
| Field | Type | Required | Description |
|---|---|---|---|
| amount | Number | ✅ | Amount in the payout currency |
| currency | String | ✅ | Currency the recipient receives (e.g. KES) |
| debitCurrency | String | ✅ | Currency to debit from your wallet (e.g. USD) |
| country | String | ✅ | Country code |
| externalReference | String | ✅ | Your own unique ID |
| payoutMethod | Object | ✅ | Recipient details |
| destination | String | ✅ | Payout destination |
Example Request:
JSON
{ "amount": 1000, "currency": "KES", "debitCurrency": "USD", "country": "KE", "externalReference": "payout_multicurrency_001", "payoutMethod": { "accountName": "John Doe", "accountNumber": "254719624552" }, "destination": "MoMo" }
Honeycoin automatically converts USD from your wallet to KES at the current exchange rate and sends the equivalent amount to the recipient.
7 - Get Payout Status
Always verify the payout status to confirm it has been processed. Use the get transaction endpoint with either:
- The transactionId from the payout response, or
- Your externalReference
Example status check:
Plain Text
GET /api/b2b/transactions?transactionId=zxcvbnmfdffdffdf
Here are examples of payout status responses:
{
"success": true,
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"amount": 1000,
"type": "withdrew",
"currency": "KES",
"chargeStatus": "pending",
"status": "PENDING",
"method": "momo",
"fullTimestamp": "2025-06-17T02:16:44+03:00",
"externalReference": "payout_seller_001"
}
}
{
"success": true,
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"amount": 1000,
"type": "withdrew",
"currency": "KES",
"chargeStatus": "successful",
"status": "SUCCESSFUL",
"method": "momo",
"fullTimestamp": "2025-06-17T02:25:44+03:00",
"externalReference": "payout_seller_001",
"thirdPartyReference": "MPESA_REF_12345"
}
}
{
"success": true,
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"amount": 1000,
"type": "withdrew",
"currency": "KES",
"chargeStatus": "failed",
"status": "FAILED",
"method": "momo",
"fullTimestamp": "2025-06-17T02:30:44+03:00",
"externalReference": "payout_seller_001",
"failureReason": "Recipient account not found"
}
}
8 - Handle Webhooks
Configure webhooks to receive real-time payout updates instead of polling the status endpoint.
Setup
1.Configure your webhook URL in your dashboard account
2.Implement webhook endpoint security and validation
3.Handle the webhook notifications in your application
Here are examples of payout webhook responses:
{
"event": "payout_created",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "pending",
"type": "withdrew",
"externalReference": "payout_seller_001",
"amount": 1000,
"currency": "KES"
},
"timestamp": "2025-06-17T02:16:44.600Z"
}
{
"event": "payout_updated",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "successful",
"type": "withdrew",
"externalReference": "payout_seller_001",
"amount": 1000,
"currency": "KES",
"method": "momo",
"completedAt": "2025-06-17T02:25:44+03:00"
},
"timestamp": "2025-06-17T02:25:44.600Z"
}
{
"event": "payout_updated",
"data": {
"transactionId": "zxcvbnmfdffdffdf",
"status": "failed",
"type": "withdrew",
"externalReference": "payout_seller_001",
"amount": 1000,
"currency": "KES",
"failureReason": "Recipient account not found"
},
"timestamp": "2025-06-17T02:30:44.600Z"
}
9 - Handle Failed Payouts
When a payout fails, you will receive a webhook notification or see the failure status when querying the transaction. Common failure reasons include:
| Failure Reason | Cause | Action |
|---|---|---|
| Recipient account not found | Invalid account number or phone number | Verify recipient details and retry |
| Insufficient wallet balance | Your account doesn't have enough funds | Top up your account and retry |
| Invalid bank code | Bank code doesn't exist or is incorrect | Verify bank code using Get Banks API |
| Recipient limit exceeded | Amount exceeds recipient's daily limit | Reduce amount or split into multiple payouts |
| Service unavailable | Payment network is temporarily down | Retry after some time |
| Invalid currency | Currency not supported for destination | Check Supported Countries & Limits |
Best Practices
- Verify recipient information before initiating payouts to reduce failed transactions
- Use external accounts for recurring payouts to the same recipients
- Implement proper error handling for failed payouts and retry logic
- Use webhooks for real-time payout updates rather than continuously polling
- Keep detailed records of all payouts for reconciliation and auditing
- Check transaction limits before initiating payouts to ensure amounts are within allowed ranges
- Test thoroughly in sandbox before deploying to production
- Monitor payout success rates to identify potential issues with recipients or payment networks
- Implement idempotency by using unique externalReference values to prevent duplicate payouts
Updated 2 days ago
