Send

Payouts

POST /v1/payouts sends money from your available balance. The header Idempotency-Key is required. AFRIPEI reserves the amount plus the fee before the payout is sent. If the balance cannot cover both, the response is 409 INSUFFICIENT_BALANCE and no payout row is created.

A payout moves real TZS. Read the balance first with GET /v1/balance. The available figure is what you can send.

How a payout works

  1. 1Read the balance. GET /v1/balance returns available, pending, and reserved amounts. Available is what a new payout can reserve.
  2. 2Create the payout. POST /v1/payouts reserves the amount plus the fee, then hands it to the rail. 409 INSUFFICIENT_BALANCE creates no row.
  3. 3Wait for the result. payout.success means the recipient was paid. payout.failed releases that reservation.

Fields

POST /v1/payouts

FieldRequiredWhat it is
amountYesDecimal string with two places, such as 10000.00.
currencyYesTZS.
methodYesmobile_money or bank.
recipient.phoneMobile moneyE.164.
recipient.nameYes for bankWallet name, or the bank account name.
recipient.account_numberBankThe account to credit.
recipient.bicBankBank identifier from GET /v1/banks.
recipient.transfer_typeBankACH or RTGS.
merchant_referenceNoYour own id for the payout.
Idempotency-KeyYesHeader. Your key, kept for 72 hours.

Mobile money

Set method to mobile_money and recipient.phone to a Tanzania number in E.164, beginning with +255. The recipient confirms nothing on a payout. The money is sent to M-Pesa, Airtel Money, Mixx by Yas, or Halopesa on that number.

Mobile money
{
  "amount": "10000.00",
  "currency": "TZS",
  "method": "mobile_money",
  "merchant_reference": "salary-1001",
  "recipient": { "phone": "+255700000000", "name": "Amina Juma" }
}

Bank transfer

Set method to bank. recipient.account_number, recipient.bic, and recipient.transfer_type are required. transfer_type is ACH or RTGS. GET /v1/banks lists the banks you can pay.

Bank transfer
{
  "amount": "250000.00",
  "currency": "TZS",
  "method": "bank",
  "merchant_reference": "supplier-44",
  "recipient": {
    "name": "Amina Supplies",
    "account_number": "0152000000000",
    "bic": "NMIBTZTZ",
    "bank_name": "NMB",
    "transfer_type": "ACH"
  }
}

Bulk

POST /v1/payouts/bulk reserves the whole batch first. Each item has its own amount and phone. A failed item releases only that item. The batch still uses one Idempotency-Key.

Bulk
{
  "currency": "TZS",
  "items": [
    { "amount": "5000.00", "phone": "+255700000000", "name": "Amina Juma" },
    { "amount": "5000.00", "phone": "+255700000001", "name": "Baraka Mushi" }
  ]
}

Response

POST /v1/payouts

A 201 means the payout was reserved and handed to the rail. fees.merchant_total is the amount plus the fee that left available balance. fees.recipient_amount is what the recipient is due. The amounts in the example are the shape, not a price list.

Response
{
  "id": "po_...",
  "object": "payout",
  "amount": "10000.00",
  "currency": "TZS",
  "status": "pending",
  "method": "mobile_money",
  "provider": "mobile_money",
  "provider_name": "Mobile money",
  "merchant_reference": "salary-1001",
  "recipient": { "phone": "+255700000000", "name": "Amina Juma" },
  "fees": {
    "afripei_fee": "0.00",
    "merchant_total": "10000.00",
    "recipient_amount": "10000.00"
  },
  "livemode": true,
  "created_at": "2026-10-20T12:00:00.000Z",
  "completed_at": null
}

Statuses

StatusMeaning
createdReserved. Not sent yet.
initiatedHanded to the rail.
pendingThe rail has accepted it and has not finished.
processingThe transfer is being applied.
successThe recipient was paid.
failedThe rail rejected it. The reservation is released.
cancelledStopped before the money left.

Read one payout with GET /v1/payouts/:id and list them with GET /v1/payouts.

Balance before you send

GET /v1/balance returns available, pending, and reserved amounts. Available is what a new payout can reserve. Pending is money that has not settled into available. Reserved is held for payouts that have not finished. A payout that is still pending stays inside reserved until it succeeds or fails.

Banks

GET /v1/banks lists the banks a payout can use. Use the identifier from that list as recipient.bic. Do not invent a bank code. transfer_type is ACH or RTGS. The account name is the name on the bank account.

What not to do

  • Do not create a payout when you have not read the balance.
  • Do not retry a timed-out create with a new idempotency key. The first request may already have reserved the money.
  • Do not treat pending as paid. Wait for payout.success.
  • Do not send a fee in the body. The fee is reserved from the rule on the account.