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.

FieldTypeRequiredDescription
amountNumberAmount to payout (e.g. 1000)
currencyStringCurrency code (e.g. KES, UGX, NGN)
countryStringISO 3166-1 alpha-2 country code (e.g. KE, UG)
externalReferenceStringYour own unique ID for reconciliation (e.g. payout_12345)
payoutMethodObjectRecipient details (see below)
destinationStringSet to MoMo for mobile money
debitCurrencyStringWallet currency to debit from (if different from payout currency)

Payout Method Object (Mobile Money):

FieldTypeRequiredDescription
accountNameStringRecipient name
accountNumberStringPhone number with country code, no plus sign (e.g. 254719624552)
codeStringMobile 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.

FieldTypeRequiredDescription
amountNumberAmount to payout
currencyStringCurrency code
countryStringISO 3166-1 alpha-2 country code
externalReferenceStringYour own unique ID for reconciliation
payoutMethodObjectRecipient bank details (see below)
destinationStringSet to Bank Account

Payout Method Object (Bank Account):

FieldTypeRequiredDescription
accountNameStringAccount holder name
accountNumberStringBank account number
codeStringBank 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):

FieldTypeRequiredDescription
accountNameStringRecipient name
accountNumberStringPaybill account number
businessNumberStringPaybill 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):

FieldTypeRequiredDescription
accountNameStringRecipient name
accountNumberStringTill 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.

FieldTypeRequiredDescription
amountNumberAmount to payout
externalReferenceStringYour own unique ID for reconciliation
externalAccountIdStringID 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.

FieldTypeRequiredDescription
amountNumberAmount in the payout currency
currencyStringCurrency the recipient receives (e.g. KES)
debitCurrencyStringCurrency to debit from your wallet (e.g. USD)
countryStringCountry code
externalReferenceStringYour own unique ID
payoutMethodObjectRecipient details
destinationStringPayout 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 ReasonCauseAction
Recipient account not foundInvalid account number or phone numberVerify recipient details and retry
Insufficient wallet balanceYour account doesn't have enough fundsTop up your account and retry
Invalid bank codeBank code doesn't exist or is incorrectVerify bank code using Get Banks API
Recipient limit exceededAmount exceeds recipient's daily limitReduce amount or split into multiple payouts
Service unavailablePayment network is temporarily downRetry after some time
Invalid currencyCurrency not supported for destinationCheck 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