A bulk payout API sends many payouts from one request or one file. Each line pays one bank account or mobile money wallet, and succeeds or fails on its own. In Africa, one batch often mixes banks and mobile money wallets, each with its own caps. Give every line its own idempotency key and replay only failed lines.
General information, not legal advice. Check current limits with your provider and the regulator.
What is a bulk payout API?
It is an API that takes a list of payouts and processes each one separately. The batch is a container. The money moves line by line. Some providers take the whole list in one call. Others take one call per line, grouped under your own batch ID.
Batch sizes vary. For example, one African payout API accepts 2 to 50 lines per batch. Another accepts up to 500 payouts per CSV upload.
Teams use bulk payouts for salaries, commissions, seller and merchant settlements, loan disbursements and remittance payouts. In Africa, one batch often mixes bank accounts and mobile money wallets across several countries. Many providers also accept a CSV upload in a dashboard, for teams without engineers.
How do you split a batch into lines?
One line per recipient, per currency and per rail. Then apply three splits.
- By currency. Some providers create one batch per currency. Each one is funded from its own balance.
- By transfer cap. Some rails cap the amount of one transfer. Split a large payment into several lines under the cap. Each line gets its own key.
- By approval. Large lines may need a second approver. Keep them apart, so small lines do not wait.
On Nigeria's NIP rail, the cap depends on the bank. NIP is NIBSS Instant Payment, Nigeria's interbank transfer system. NIBSS says the NIP limit follows guidelines from the CBN, the Central Bank of Nigeria. Each bank's maximum is set on the platform. Ask your provider for its ceiling on each rail.
Payment teams often ask for maker-checker approval. One user uploads the batch, and a second user approves it. Amount thresholds decide how many approvals a line needs.
How do you stop a batch from paying someone twice?
Give each line a unique idempotency key before you send it. An idempotency key is an ID you create and send with the request. If the same key arrives twice, the provider returns the first payout. It does not create a second one.
Store the key with the line before the call. A timeout then becomes safe. You resend with the same key and get the original payout back.
Check how your provider handles four cases.
- Same key, same details. The original payout comes back, often flagged as a replay.
- Same key, new details. The provider returns an error. The code varies, for example 409, 422 or 400.
- Response lost. Some APIs let you search payouts by key and recover the line.
- Key expired. Providers keep keys for a limited time. After that, the same key can create a new payout. Query by your reference before you resend an old line.
MTN's MoMo API also blocks duplicates, in a different way. A repeated reference ID gets the error RESOURCE_ALREADY_EXIST. MTN does not return the first payment. Query the status by that reference ID instead. MTN asks for a new UUID, a random unique ID, for each payment request.
What happens when part of a batch fails?
The good lines pay and the bad lines fail. Do not read the batch status as the result. Read the status of each line. Some providers mark the batch complete and show a count of failed lines. One calls this state "completed with errors".
Sort the failed lines into two groups.
- Failed for sure. The line has a final failed status and a reason. Fix the data, then send the line again with a new key. The old key belongs to the failed payout. On APIs built this way, reusing it returns that failure, or an error if details changed.
- Unknown. No final status yet. Keep the same key. Query the status first, by payout ID or by key. Resend only once the provider confirms the failure.
Ask when a failed line's amount returns to your balance. Some providers reverse the debit on their own. Others need a request.
Why do payouts fail, rail by rail?
Most rows below are recipient data problems. MTN codes come from MTN's list of 11 February 2025.
| Rail | Common failure | What to check before you send |
|---|---|---|
| Bank, Nigeria (NIP) | Account name differs from the name you hold | Run a name enquiry. NIBSS describes it as checking the beneficiary's details from the account number. Compare names before you pay. |
| Bank, Nigeria (NIP) | Amount above the bank's limit for one transfer | Split the line. Ask your provider for the ceiling. |
| Bank, any rail | Reference rejected | Keep references short, with letters, digits and few symbols. Ask for each rail's length and character rules. |
| Mobile money | Number invalid or not registered | Use the format your provider asks for: country code plus number, no spaces. |
| Mobile money | Wallet inactive or blocked | MTN returns PAYEE_NOT_ALLOWED_TO_RECEIVE. Ask the recipient for another number. |
| Mobile money | Wallet at its limit | MTN returns "PAYEE LIMIT_REACHED". Match on the raw string. Lower the amount or split it over days. |
| Mobile money | Wallet KYC too low, or lapsed | KYC means know your customer. Ask the recipient to upgrade or renew it. |
| Mobile, Côte d'Ivoire | Old 8-digit number in your records | Numbers have 10 digits since 31 January 2021. Orange adds 07, MTN 05 and Moov 01. |
MTN's 2025 list reads NOT_ENOUGH_FUNDS as the payer lacking funds. On a payout, the payer is you. So check your own balance first. A January 2024 MTN note had mapped a receiver's limit breach to that code. Log the raw code and the date you saw it.
Which mobile money limits apply by country?
Limits sit on the recipient's wallet. A payout that takes a wallet over its cap fails. WAEMU is the West African Economic and Monetary Union. Its eight countries use the XOF, including Côte d'Ivoire and Senegal. Its central bank is the BCEAO.
| Country or zone | Limit | Rule and date |
|---|---|---|
| Kenya, all mobile money wallets | Maximum KES 250,000 per transaction. Maximum KES 500,000 wallet balance. A provider may set lower. | CBK, the Central Bank of Kenya, in force from 15 August 2023. No later change found on 14 October 2026. |
| WAEMU, until 1 November 2026 | FCFA 2 million balance. FCFA 10 million in top-ups a month. | BCEAO Instruction 008-05-2015 of 21 May 2015, identified holders. |
| WAEMU, from 2 November 2026 | FCFA 4 million balance, per identified client, per issuer, summed across all instruments. FCFA 15 million in top-ups a month. The BCEAO can authorise more. | BCEAO Instruction n°020, signed 8 October 2026, in force 2 November 2026. |
| Nigeria | Caps by KYC tier on accounts and wallets | CBN tiered KYC. Ask your provider for the tier limits it applies. |
| Ghana, Uganda, Cameroon and CEMAC | Limits exist by KYC level and by provider | Ask your provider for current figures per wallet type. |
An issuer is the company that holds the e-money, such as a mobile money operator. In WAEMU, the caps do not apply to distributors and merchants acting in a professional capacity. Update your pre-checks before 2 November 2026. Safaricom also lists a daily transaction limit of KES 500,000. See M-Pesa payouts for the rail itself, and a separate guide on the XOF and XAF zones.
Which statuses and webhooks should you track?
Track each line, from creation to one final state. A typical lifecycle runs: created, validated, sent to the rail. It then ends as completed, failed or canceled.
A webhook is a message the provider posts to your server when a status changes. Several African payout APIs send one webhook per line in the batch. Ask for one event per line when it reaches a final state.
- Treat each webhook as a trigger. Then fetch the line to confirm it.
- Handle the same event twice without booking it twice.
- Store the failure reason with the line.
- Some lines stop for a document, such as an invoice, or a compliance question. Give them their own state, so they do not sit as pending.
- Poll any line still open after your cut-off time.
What funding does a batch need?
Fund the full batch before you send it. Many providers debit a balance you hold with them. If the balance runs short, behaviour depends on the provider. Some reject the whole batch. Others pay lines until the balance runs out.
If the batch converts currency, ask how long a quote lasts. Quotes expire, and a large batch can outlive one. Ask whether each line gets its own rate, or one quote covers the batch.
What should the reconciliation file contain?
One row per line, with IDs from both sides. Finance matches on your reference and the provider's payout ID. Then it checks amount, currency, recipient, status and date.
| Column | Why finance needs it |
|---|---|
| Batch ID | Groups lines for approval and reporting |
| Your line ID and idempotency key | Links the payout to your ledger and to retries |
| Provider payout ID | The ID for any query to the provider |
| Rail reference | The bank or operator's own transaction ID |
| Recipient name and account or wallet, masked | Shows who was paid |
| Source amount and currency | What left your balance |
| Target amount and currency | What the recipient received |
| Quote ID or rate applied | Explains the conversion |
| Status and time of final status | Completed, failed or canceled, and when |
| Failure reason | The provider's text and the rail's code |
| Replaces line | The line ID this line retries, if any |
| Returned after completion | Flag and date, if money came back later |
| Approved by | Who approved the line |
For SWIFT lines, the rail record is the MT103. See how to read an MT103.
Check which payer name the recipient sees. A pooled account is one account a provider uses for many clients. A payout from it can show the provider's name. The recipient then struggles to match it to an invoice. Ask what payer name each rail displays.
What should you ask a bulk payout provider?
- Is there a batch endpoint, or one call per line? What is the batch size limit?
- Is idempotency set per line? How long do you keep a key?
- Do you send one webhook per line? Which final states exist?
- Which bank and operator failure codes do you pass through?
- Do you run a name enquiry on NIP before paying?
- What is your ceiling for one transfer on each rail?
- When does a failed line's amount return to our balance?
- What payer name does the recipient see on each rail?
- Can we export one row per line with the columns above?
FAQ
What is a bulk payout API?
It is an API that takes a list of payouts and processes each one separately. The batch is a container. The money moves line by line.
What happens when part of a batch fails?
The good lines pay and the bad lines fail. Do not read the batch status as the result. Read the status of each line.
Can I resend a failed payout with the same idempotency key?
No. Fix the data, then send the line again with a new key. The old key belongs to the failed payout.
What should I do with a payout that timed out?
Keep the same key. Query the status first, by payout ID or by key. Resend only once the provider confirms the failure.
What does NOT_ENOUGH_FUNDS mean on an MTN MoMo payout?
MTN's 2025 list reads NOT_ENOUGH_FUNDS as the payer lacking funds. On a payout, the payer is you. So check your own balance first.
What is the M-Pesa limit for one payout in Kenya?
Maximum KES 250,000 per transaction. Maximum KES 500,000 wallet balance. A provider may set lower.
What are the WAEMU mobile money limits from 2 November 2026?
FCFA 4 million balance, per identified client, per issuer, summed across all instruments. FCFA 15 million in top-ups a month. The BCEAO can authorise more.
What columns does a payout reconciliation file need?
One row per line, with IDs from both sides. Finance matches on your reference and the provider's payout ID. Then it checks amount, currency, recipient, status and date.
For PSPs, fintechs and remitters
If you pay out across Africa for your clients, talk to our team about payouts across Africa. Rails and countries are on our payouts page.