How a mobile money payout works
Both providers send money from your balance to a wallet, and both answer straight away with "queued". The result comes later, so the request on its own never means the money arrived.
| Paystack | Flutterwave (v3) | |
|---|---|---|
| Countries here | Ghana (MTN, Telecel, AT), Kenya (M-Pesa) | Uganda (MTN, Airtel) |
| Before the first payout | Create a recipient once per wallet (POST /transferrecipient) | Nothing: the number goes in each transfer |
| Send | POST /transfer | POST /v3/transfers |
| Amount | Subunits: 25.50 GHS is 2550 | Whole shillings: 50000 |
| Phone format | Local: 0551234987 | With the country code: 256772123456 |
| Look it up | By your reference: GET /transfer/verify/:reference | By their id: GET /v3/transfers/:id |
| Final statuses | success, failed, reversed, abandoned, blocked, rejected | SUCCESSFUL, FAILED |
After a timeout: the one rule that matters
A timed-out payout request may still have gone through. Never send it again with a new reference: that can pay twice. On Paystack, verify it by your reference; if Paystack has never seen it, send it again with the same reference. On Flutterwave, you need the transfer id to look it up, and a lost response means you don't have it. Mark the payout unknown and wait for thetransfer.completed webhook, which carries your reference and the id. Flutterwave's docs say a timeout is a 503 after about 28 seconds and the transfer may still be processing.
Before you send real money
- Paystack transfers need a registered business. Transfers need an OTP by default: untick Confirm transfers before sending in Preferences to send from code.
- Paystack's docs don't state the phone format for Kenyan recipients. The builder uses the local format, as in its Ghana example: confirm it with one small live payout.
- Flutterwave's mobile money page lists
Airtel,MPSandMTNfor Uganda. The builder sendsMTNorAirtel, picked from the number; confirm it in test mode. - Save each payout, with its reference, in your database before sending it, and only ever send from a "new" status.
What each status and error means: Paystack error reference and Flutterwave error reference.
Frequently asked questions
What bank_code do I use for a mobile money wallet on Paystack?
The network: MTN, VOD (Telecel) or ATL (AT) in Ghana, and MPESA in Kenya, with type mobile_money. This builder picks the code from the phone number. You can list the codes on your account with GET /bank?currency=GHS&type=mobile_money.
Why is my Paystack transfer amount 100 times too small?
Paystack amounts are in the subunit: pesewas for GHS, cents for KES. 25.50 GHS is sent as 2550. The builder converts the amount you type, without floating point.
My transfer request timed out. Can I send it again?
On Paystack, verify it by your reference first, and only send again, with the same reference, if Paystack has never seen it. On Flutterwave you look transfers up by their id, which you don't have if the response was lost, so don't resend: wait for the transfer.completed webhook, which carries your reference and the id.
Is "Transfer has been queued" or "Transfer Queued Successfully" a completed payout?
No. Both mean the provider accepted the transfer. It is complete only when the lookup says success (Paystack) or SUCCESSFUL (Flutterwave). On Paystack, a success can still become reversed later.
Is it safe to paste my secret key here?
The page runs entirely in your browser and sends nothing anywhere, but only ever use a test key. Live keys are refused and left out of the code. The default is to read the key from an environment variable.
Full integrations
- Paystack payouts: Node.js, Laravel, Django: never paying twice, webhooks, reversals and tests.
- Flutterwave payouts: Node.js, Laravel, Django.
- Mobile money payouts compared: Paystack, Flutterwave, MTN MoMo Disbursements and M-Pesa B2C.
- MTN MoMo Request Builder: the same for MoMo Disbursements.
- Paystack Webhook Checker and Flutterwave Webhook Checker: check the transfer webhooks.
Endpoints and fields checked November 2026 against Paystack's transfer documentation and Flutterwave's v3 documentation.