Skip to content

Payout / Alternative payment methods / Africa

Mobile Money#

POST https://payments.apipro.io/v2/payout

The ApiPro Payout API allows you to send funds to your clients' mobile money accounts. This document provides instructions on how to create and manage these payouts.

How Mobile Money Payouts Work#

  1. Request: Your application makes a POST request to the ApiPro payout endpoint to create a transaction.
  2. Processing: ApiPro processes the payout, interacting with the appropriate mobile money provider.
  3. Notification: Once the transaction reaches a terminal state (e.g., success or error), ApiPro sends a callback (webhook) to your specified callback_url.

Available Operators#

  • Kenya (KE): mpesa, airtel
  • Tanzania (TZ): vodacom, tigo, halopesa, airtel
  • Ghana (GH): vodafone, mtn, airteltigo
  • Gambia (GM): qcell, wave, africel
  • Cameroon (CM): fmm, orange, mtn
  • Ivory Coast (CI): orange, mtn, moov, wave
  • Zambia (ZM): airtel, mtn, safaricom, zamtel
  • Malawi (MW): airtel, tnm mpamba
  • Rwanda (RW): safaricom
  • Republic of the Congo (CG): fmm
  • Uganda (UG): airtel, mtn, safaricom
  • Benin (BJ): fmm, wave, emoney, freemoney, orange
  • Burkina Faso (BF): fmm, wave, emoney, freemoney, orange, mobicash
  • Guinea-Bissau (GW): fmm, wave, emoney, freemoney, orange
  • Côte d'Ivoire (CI): fmm, wave, emoney, freemoney, orange, mtn
  • Mali (ML): fmm, wave, emoney, freemoney, orange
  • Niger (NE): fmm, wave, emoney, freemoney, orange
  • Senegal (SN): fmm, wave, emoney, freemoney, orange
  • Togo (TG): tmoney, fmm, wave, emoney, freemoney, orange
  • Ethiopia (ET): amolemoney
  • Guinea (GN): mtn
  • Egypt (EG): wepay, etisalat
  • Mozambique (MZ): vodacom
  • Zimbabwe (ZW): ecocash
  • Central African Republic (CF): fmm
  • Chad (TD): fmm
  • Gabon (GA): fmm
  • Equatorial Guinea (GQ): fmm

Headers#

Header Value
Content-Type application/json
Authorization {{authorization}}
Digest {{digest}}
Host {{host}}
Date {{date}}

See Authentication & Signature for how to build the signed headers.

Request body#

Annotations in the example are the field requirements: required, optional or conditional. Comments are stripped automatically by the Postman collection before signing; remove them in your own requests.

{
    "method": "mobile_money", // required, snake_case / lower case only: "mobile_money" (not "MOBILE_MONEY" or "MobileMoney")
    "reference": "KenyaPayoutTransaction#1", // required, unique
    "currency": "KES", // required
    "amount": 21, // required
    "description": "My order payout", // optional
    "mobile_money": { // required
        "phone": "+254712973246", // required
        "operator": "mpesa", // conditional
        "beneficiary_first_name": "Oki", // conditional
        "beneficiary_last_name": "Doki", // conditional
        "beneficiary_document_type": "national_id", // conditional
        "beneficiary_document_value": "7876543" // conditional
    },
    "customer": { // required
        "identifier": "1111-1111-2211-2211", // required
        "email": "juancarlos@hotmail.com", // conditional
        "phone": "+254712973246", // conditional
        "first_name": "Juan", // required
        "last_name": "García Rodríguez", // required
        "middle_name": "Carlos", // optional
        "country": "KE", // optional
        "state_code": "B", // optional
        "city": "Buenos Aires", // optional
        "address": "Calle Emilio Mitre 3256", // optional
        "zip_code": "C1407", // optional
        "itn": "12345678910", // optional
        "birthday": "2006-01-02", // optional
        "ip": "192.168.0.1", // optional
        "gender": "male" // optional
    },
    "callback_url": "https://merchant.shop.com/callback/success", // conditional
    "extra": { // conditional, any field which may be needed for transaction routing and integration
        "meta": {
            "key": "value"
        }
    }
}

Fields#

Field Type Requirement / note
method string required, snake_case / lower case only: "mobile_money" (not "MOBILE_MONEY" or "MobileMoney")
reference string required, unique
currency string required
amount integer required
description string optional
mobile_money object required
mobile_money.phone string required
mobile_money.operator string conditional
mobile_money.beneficiary_first_name string conditional
mobile_money.beneficiary_last_name string conditional
mobile_money.beneficiary_document_type string conditional
mobile_money.beneficiary_document_value string conditional
customer object required
customer.identifier string required
customer.email string conditional
customer.phone string conditional
customer.first_name string required
customer.last_name string required
customer.middle_name string optional
customer.country string optional
customer.state_code string optional
customer.city string optional
customer.address string optional
customer.zip_code string optional
customer.itn string optional
customer.birthday string optional
customer.ip string optional
customer.gender string optional
callback_url string conditional
extra object conditional, any field which may be needed for transaction routing and integration
extra.meta object
extra.meta.key string

Responses#

Response Examples

Succesful transaction
{
  "identifier": "MOB000137185",
  "request_id": "6ae8671e-6b6f-4678-981a-36a783aa73ec",
  "reference": "KenyaPayoutTransaction#1",
  "description": "My order payout",
  "status": {
    "name": "pending",
    "date": "2025-08-27T08:27:49.014"
  },
  "created_date": "2025-08-27T08:27:45.764",
  "amount": 21,
  "billing_amount": 21,
  "currency": "KES",
  "extra": [
    {
      "key": "key_2",
      "value": "value"
    },
    {
      "key": "key_3",
      "value": "value"
    },
    {
      "key": "key_4",
      "value": "value"
    },
    {
      "key": "key_1",
      "value": "value"
    }
  ],
  "timestamp": "2025-08-27T08:27:49.2818969Z",
  "error_code": 0,
  "error_message": ""
}
Card can only be used with specific methods. Check documentation
{
  "error_code": 30,
  "error_reason": "Invalid params",
  "description": "Card can only be used with specific methods. Check documentation",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:05:00.00Z"
}
Customer is blocked
{
  "error_code": 451,
  "error_reason": "General risk decline",
  "description": "Customer is blocked",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:06:00.00Z"
}
Customer is blocked for all merchant projects
{
  "error_code": 451,
  "error_reason": "General risk decline",
  "description": "Customer is blocked for all merchant projects",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:08:02.00Z"
}
Customer is blocked for the specified project
{
  "error_code": 451,
  "error_reason": "General risk decline",
  "description": "Customer is blocked for the specified project",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:08:04.00Z"
}
Customer is blocked system-wide
{
  "error_code": 451,
  "error_reason": "General risk decline",
  "description": "Customer is blocked system-wide",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:08:06.00Z"
}
Customer is globally locked
{
  "error_code": 451,
  "error_reason": "General risk decline",
  "description": "Customer is globally locked",
  "request_id": "YOUR_REFERENCE",
  "status": "error",
  "timestamp": "2025-10-26T14:08:08.00Z"
}
Resource not found
{
  "error_code": 35,
  "error_reason": "Resource not found",
  "description": "The requested resource is undefined",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:15:00.00Z"
}
Routing failed
{
  "error_code": 121,
  "error_reason": "Routing failed",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Unknown routing error
{
  "error_code": 1,
  "error_reason": "Unknown routing error",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Routing service error: Value cannot be null. (Parameter 'data')
{
  "error_code": 1,
  "error_reason": "Routing service error: Value cannot be null. (Parameter 'data')",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Routing request timeout
{
  "error_code": 2,
  "error_reason": "Routing request timeout",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Required fields are missing: method, reference, amount, currency
{
  "error_code": 31,
  "error_reason": "Required fields are missing: method, reference, amount, currency",
  "timestamp": "2025-10-02T14:16:00.00Z"
}
Routing service error: Endpoint type cannot be null or empty
{
  "error_code": 1,
  "error_reason": "Routing service error: Endpoint type cannot be null or empty",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Routing service error
{
  "error_code": 1,
  "error_reason": "Routing service error",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Payment transaction timeout after seconds
{
  "error_code": 1,
  "error_reason": "Payment transaction timeout after 30 seconds",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Internal error: Mid {MidId} no longer exists in configuration
{
  "error_code": 1,
  "error_reason": "Internal error: Mid {MidId} no longer exists in configuration",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Internal error: Value cannot be null. (Parameter 'tcs')
{
  "error_code": 1,
  "error_reason": "Internal error: Value cannot be null. (Parameter 'tcs')",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Payment transaction was cancelled
{
  "error_code": 1,
  "error_reason": "Payment transaction was cancelled",
  "timestamp": "2025-10-02T14:17:00.00Z"
}
Error while trying to process filling data
{
  "error_code": 200,
  "error_reason": "Error while trying to process filling data",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:18:00.00Z"
}
Invalid method challenge configuration. Please reconfigure method challenge type settings
{
  "error_code": 121,
  "error_reason": "Invalid method challenge configuration. Please reconfigure method challenge type settings",
  "timestamp": "2025-10-02T14:19:00.00Z"
}
There is more than one challenge setting for a method. Please reconfigure method challenge type settings
{
  "error_code": 121,
  "error_reason": "There is more than one challenge setting for a method. Please reconfigure method challenge type settings",
  "timestamp": "2025-10-02T14:20:00.00Z"
}
MID not found in cache while getting currency rate
{
  "error_code": 35,
  "error_reason": "Resource not found",
  "description": "MID not found in cache while getting currency rate",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:21:00.00Z"
}
Transaction processing error: error while getting currency rate
{
  "error_code": 200,
  "error_reason": "Transaction processing error",
  "description": "Unexpected error while getting currency rate",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:22:00.00Z"
}
Transaction processing error: error with payment configurations during calculation
{
  "error_code": 200,
  "error_reason": "Transaction processing error",
  "description": "Error with payment configurations during calculation",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:23:00.00Z"
}
Exceeded amount limits for project
{
  "error_code": 1132,
  "error_reason": "Limit exceeded",
  "description": "Amount is outside the allowed project limits",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:24:00.00Z"
}
Exceeded amount limits for MID
{
  "error_code": 1132,
  "error_reason": "Limit exceeded",
  "description": "Amount is outside the allowed MID limits",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:24:00.00Z"
}
Transaction processing error: error while getting withdrawal rates
{
  "error_code": 200,
  "error_reason": "Transaction processing error",
  "description": "Unexpected error while getting withdrawal rates",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:24:00.00Z"
}
Invalid params: transactions constraints were violated
{
  "error_code": 30,
  "error_reason": "Invalid params",
  "description": "Transaction contraints were violated",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:26:00.00Z"
}
Failed to create transaction for unfamiliar reason
{
  "error_code": 200,
  "error_reason": "Transaction processing error",
  "description": "Failed to create transaction",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:27:00.00Z"
}
Account payout has negative balance after update
{
  "error_code": 1,
  "error_reason": "Insufficient funds on account",
  "description": "Account payout has negative balance after update",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:28:00.00Z"
}
Error with wallet
{
  "error_code": 200,
  "error_reason": "Transaction processing error",
  "description": "Error with wallet",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:29:00.00Z"
}
Mid is disabled
{
  "error_code": 32,
  "error_reason": "Invalid MID",
  "description": "Mid is disabled",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:30:00.00Z"
}
Blocked routing for transaction: Invalid currency
{
  "error_code": 31,
  "error_reason": "Invalid currency",
  "description": "Blocked routing for transaction: Invalid currency",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:31:00.00Z"
}
Blocked routing for transaction: Invalid method
{
  "error_code": 1054,
  "error_reason": "Invalid method",
  "description": "Blocked routing for transaction: Invalid method",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:32:00.00Z"
}
Blocked routing for transaction: Invalid payment type
{
  "error_code": 1054,
  "error_reason": "Invalid type",
  "description": "Blocked routing for transaction: Invalid payment type",
  "request_id": "value_from_data_reference",
  "status": "error",
  "timestamp": "2025-10-02T14:33:00.00Z"
}
Requisites - Invalid JSON format
{
  "error_code": 31,
  "error_reason": "Required fields are missing: requisites - invalid JSON format",
  "timestamp": "2025-10-02T14:34:00.00Z"
}
Mid configuration error
{
  "error_code": 200,
  "error_reason": "Mid configuration error",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:35:00.00Z"
}
Mid request timeout
{
  "error_code": 200,
  "error_reason": "Mid request timeout",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:36:00.00Z"
}
Communication error
{
  "error_code": 200,
  "error_reason": "Communication error",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:36:00.00Z"
}
Invalid adapter response format
{
  "error_code": 200,
  "error_reason": "Invalid adapter response format",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:37:00.00Z"
}
Failed to register card transaction
{
  "error_code": 200,
  "error_reason": "Failed to register card transaction",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:48:00.00Z"
}
Failed to register cascade transaction
{
  "error_code": 200,
  "error_reason": "Failed to register cascade transaction",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:48:00.00Z"
}
Mid with ID '[MidId]' not found
{
  "error_code": 200,
  "error_reason": "Mid with ID '[MidId]' not found",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:49:00.00Z"
}
Mid [MidName] ([MidId]) is not active
{
  "error_code": 200,
  "error_reason": "Mid [MidName] ([MidId]) is not active",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:49:00.00Z"
}
Mid [MidId] no longer exists in configuration
{
  "error_code": 200,
  "error_reason": "Mid [MidId] no longer exists in configuration",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:49:00.00Z"
}
Some unexpected error occured
{
  "error_code": 200,
  "error_reason": "<Some unexpected error message>",
  "request_id": null,
  "reference": "value_from_data_reference",
  "timestamp": "2025-10-02T14:49:00.00Z"
}
Request cannot be null
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Request cannot be null",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Flow cache limit exceeded
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Flow cache limit exceeded",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Flow configuration not found for project: {projectId}
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Flow configuration not found for project: {projectId}",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Invalid flow configuration
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Invalid flow configuration",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Flow execution failed: some unexpected error
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Flow execution failed:",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Node not found: {NodeIdentifier}
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Node not found: {NodeIdentifier}",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Flow execution limit exceeded
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Flow execution limit exceeded",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Flow ended without result
{
  "code": 0,
  "reason": "",
  "error_code": 1,
  "error_reason": "Flow ended without result",
  "request_id": "",
  "reference": "",
  "status": "error",
  "timestamp": "2025-09-29T11:52:39.25Z",
  "description": ""
}
Success transaction
{
  "request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "identifier": "PT_MM_Z9Y8X7W6V5",
  "reference": "MM-PAYOUT-2023-556",
  "creation_date": "2023-11-22T10:05:30.543210",
  "method": "mobile_money",
  "type": "payout",
  "mode": "initial",
  "status": "success",
  "status_date": "2023-11-22T10:05:33.123456",
  "amount": "5000.00",
  "currency": "NGN",
  "billing_amount": "5000.00",
  "billing_currency": "NGN",
  "fee_amount": "25.50",
  "fee_currency": "NGN",
  "customer": {
    "identifier": "CUST-MM-12345",
    "email": "adekunle.gold@example.com",
    "first_name": "Adekunle",
    "last_name": "Gold",
    "phone": "2348098765432",
    "country": "NG",
    "city": "Ibadan",
    "address": "55 Liberty Road",
    "zip_code": "200223",
    "birthday": "1992-08-20",
    "ip": "196.46.244.15"
  },
  "mobile_money": {
    "phone": "2348031234567",
    "operator": "airtel"
  },
  "error_code": 0,
  "error_reason": "",
  "timestamp": "2023-11-22T10:05:35.987654"
}
Duplicated reference
{
  "error_code": 108,
  "error_reason": "Duplicated reference",
  "request_id": "3829f5bd-6dcb-41f9-a4ba-3ff8b65a3cfc",
  "reference": "",
  "timestamp": "2025-11-10T08:47:22.81Z"
}
'mobile_money' missing field
{
  "error_code": 31,
  "error_reason": "Required fields are missing: mobile_money",
  "timestamp": "2025-10-02T14:25:00.00Z"
}
Invalid Authorization header format
{
  "error_code": 31,
  "error_reason": "Invalid Authorization header format",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid Signature format
{
  "error_code": 31,
  "error_reason": "Invalid signature format",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Unsupported algorithm
{
  "error_code": 31,
  "error_reason": "Unsupported algorithm",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid API key
{
  "error_code": 31,
  "error_reason": "Invalid API key",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid date format
{
  "error_code": 31,
  "error_reason": "Invalid date format",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Date is outdated or invalid
{
  "error_code": 31,
  "error_reason": "Date is outdated or invalid",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Missing Digest header
{
  "error_code": 31,
  "error_reason": "Invalid digest",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid digest
{
  "error_code": 31,
  "error_reason": "Missing Digest header",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid signature
{
  "error_code": 31,
  "error_reason": "Invalid signature",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Invalid headers specification
{
  "error_code": 31,
  "error_reason": "Invalid headers specification",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Request timestamp has already been used
{
  "error_code": 31,
  "error_reason": "Request timestamp has already been used",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Missing required authentication headers
{
  "error_code": 31,
  "error_reason": "Missing required authentication headers",
  "timestamp": "2025-10-26T14:04:00.00Z"
}
Missing Authorization header
{
  "error_code": 31,
  "error_reason": "Missing Authorization header",
  "timestamp": "2025-10-26T16:01:00.00Z"
}
Missing Date header
{
  "error_code": 31,
  "error_reason": "Missing Date header",
  "timestamp": "2025-10-26T16:06:00.00Z"
}
Processing error:
{
  "error_code": 210,
  "error_reason": "Processing error:",
  "description": "Processing error:",
  "request_id": "your_transaction_reference",
  "status": "error",
  "timestamp": "2025-10-26T12:03:00.000Z"
}