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.

When To Use This

Use this guide when you want to send funds from your Honeycoin balance to a recipient through mobile money, bank transfer, M-Pesa Paybill, M-Pesa Till, or a saved external account.

All payout destinations use the same payout endpoint. The main difference between payout types is the destination value and the shape of payoutMethod.

Happy Path

  1. Confirm the recipient's country, currency, destination type, and account details.

  2. Retrieve any required destination code, such as a mobile money operator ID or bank code.

  3. Submit a payout request with a unique externalReference.

  4. Store the returned transactionId and initial status.

  5. Listen for webhook updates and reconcile the final status with your externalReference.

Destination Requirements

DestinationUse CaseRequired payoutMethod FieldsNotes
MoMoMobile money wallet payoutaccountName, accountNumber, sometimes codecode is the mobile money operator ID when operator selection is required
Bank AccountBank transfer payoutaccountName, accountNumber, codecode is the bank code from the Get Banks API
PaybillKenya M-Pesa Paybill payoutaccountName, accountNumber, businessNumberKenya only
TillKenya M-Pesa Till payoutaccountName, accountNumberKenya only
External accountRepeat payout to a saved recipientexternalAccountIdOmit currency, country, destination, and payoutMethod when using externalAccountId

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
amountNumber✅Amount to payout (e.g. 1000)
currencyString✅Currency the recipient receives (e.g. KES, UGX)
countryString✅ISO 3166-1 alpha-2 country code (e.g. KE, UG)
externalReferenceString✅Your own unique ID for reconciliation (e.g. payout_12345)
payoutMethodObject✅Recipient details (see below)
destinationString✅Set to MoMo for mobile money
debitCurrencyString❌Wallet currency to debit from (if different from payout currency)
debitCountryStringConditionalCountry scope of the wallet being debited. Required whenever debitCurrency is XOF, even for same-currency payouts. Optional for other debit currencies, including USD; omit when debitCurrency is absent.

Payout Method Object (Mobile Money):

FieldTypeRequiredDescription
accountNameString✅Recipient name
accountNumberString✅Phone number with country code, no plus sign (e.g. 254719624552)
codeString❌Mobile money operator ID when operator selection is required

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
amountNumber✅Amount to payout
currencyString✅Currency code
countryString✅ISO 3166-1 alpha-2 country code
externalReferenceString✅Your own unique ID for reconciliation
payoutMethodObject✅Recipient bank details (see below)
destinationString✅Set to Bank Account
debitCurrencyString❌Wallet currency to debit from
debitCountryStringConditionalCountry scope of the wallet being debited. Required whenever debitCurrency is XOF, even for same-currency payouts. Optional for other debit currencies, including USD; omit when debitCurrency is absent.

Payout Method Object (Bank Account):

FieldTypeRequiredDescription
accountNameString✅Account holder name
accountNumberString✅Bank account number
codeString✅Bank code (retrieve from Get Banks API)

To retrieve the correct bank code, use the Get Banks API:

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, use the same top-level payout fields and set destination to Paybill.

Payout Method Object (Paybill):

FieldTypeRequiredDescription
accountNameString✅Recipient name
accountNumberString✅Paybill account number
businessNumberString✅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, use the same top-level payout fields and set destination to Till.

Payout Method Object (Till):

FieldTypeRequiredDescription
accountNameString✅Recipient name
accountNumberString✅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.

When using externalAccountId, omit currency, country, destination, and payoutMethod. Honeycoin uses the saved destination details on the external account.

FieldTypeRequiredDescription
amountNumber✅Amount to payout
externalReferenceString✅Your own unique ID for reconciliation
externalAccountIdString✅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. Include debitCountry whenever debitCurrency is XOF, even if the payout is also in XOF. For other debit currencies, including USD, it is optional; supply the country to select the intended wallet scope. Omit debitCountry when debitCurrency is absent.

FieldTypeRequiredDescription
amountNumber✅Amount in the payout currency
currencyString✅Currency the recipient receives (e.g. KES)
debitCurrencyString✅Currency to debit from your wallet (e.g. USD)
debitCountryStringConditionalCountry scope of the wallet being debited. Required whenever debitCurrency is XOF, even for same-currency payouts. Optional for other debit currencies, including USD; omit when debitCurrency is absent.
countryString✅Recipient payout country code
externalReferenceString✅Your own unique ID
payoutMethodObject✅Recipient details
destinationString✅Payout destination

Example Request:

{
  "amount": 1000,
  "currency": "KES",
  "debitCurrency": "USD",
  "debitCountry": "US",
  "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:

GET /api/b2b/transactions/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