Payout / Alternative payment methods / Africa / Bank Transfer
Payout#
GET https://payments.apipro.io/v2/payout
The ApiPro Payout API allows you to send funds to your clients' bank accounts in Africa. This document provides instructions on how to create and manage these bank transfer payouts.
How Bank Transfer Payouts Work#
There are two primary flows for processing a bank transfer payout.
Scenario 1: Pre-selected Bank (Recommended Flow)
- Your application initiates a request to retrieve the list of available banks.
- You display this list to the customer, who selects their bank and provides their account number and other required details.
- You make a request to create the payout, including the
bank_codeselected by the user. - Our system processes the payout and interacts with the provider.
- We send a webhook (callback) to your server once the transaction reaches a terminal status (e.g.,
successorerror).
ℹ️ InfoIf the banking provider does not support the bank specified by the user, the transaction will be declined.
Scenario 2: Payout with bank_code Challenge
- You make a request to create a payout without providing the
bank_transfer_africa.bank_codefield. - Our system processes the request and responds with a
challengeobject containing a list of available banks. - You handle this challenge by displaying the list of banks to the user.
- The customer selects their bank from the list.
- You send a request to confirm the challenge with the selected
bank_code. - We send a webhook to your server once the transaction reaches a terminal status.
Step 1 (Optional): Get List of Banks#
To allow the user to select their bank upfront, you can retrieve a list of all supported banks for a specific country.
Request#
GET https://payments.apipro.io/v2/bank/africa?country_code={country_code}
Response - 200 OK#
[
{
"name": "Access Bank Nigeria", // Full name of the bank
"code": "044", // The code to use in the payout request
"country": "NG"
}
]
Step 2: Create Payout#
Response Handling#
First, you should always check the error_code field. If error_code is not 0, the transaction has failed.
Second, check the status field.
- If you get a pending status and the challenge object is absent, you should wait for a callback or use the Check endpoint to get the final status.
- If you get a pending status with a bank_code challenge, please follow the instructions in the next section.
Response Example: Pending with bank_code challenge#
{
"error_code": 0,
"error_reason": "",
"request_id": "caa8f24b-0183-4c1f-8b23-e4870a533306",
"reference": "order-00001",
"status": "pending",
"type": "payout",
"method": "bank_transfer_africa",
"mode": "initial",
"currency": "NGN",
"amount": "25.01",
"challenge": {
"challenge_type": "bank_code",
"challenge_bank_code": [
{
"name": "Wema Bank",
"code": "035",
"country": "NG"
},
{
"name": "Access Bank Nigeria",
"code": "044",
"country": "NG"
}
]
},
"timestamp": "2024-02-01T15:57:19Z"
}
Handling the bank_code Challenge#
This challenge occurs if you create a payout request without the bank_transfer_africa.bank_code field. You must:
- Display the list of banks from the challenge.challenge_bank_code array to the user.
- After the user selects a bank, send a confirmation request with their choice.
- Wait for the final status via callback.
Challenge Confirmation Request#
POST https://payments.apipro.io/v2/payout/challenge/bank-code
{
"reference": "order1112",
"bank_code": "044"
}
A successful confirmation will return a 200 OK response with an empty body.
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.
Responses#
Response Examples
Succesful transaction
{
"identifier": "BAN000442148",
"request_id": "4683afaa-5a18-40ac-b42b-7ceac10d7f7a",
"reference": "AfricaBankTransferPayout#1",
"description": "Payout for Kristina Shepel",
"status": {
"name": "created",
"date": "2025-10-13T09:15:33.782"
},
"created_date": "2025-10-13T09:15:31.46",
"amount": 165,
"billing_amount": 165,
"currency": "NGN",
"requisites": {
"account_number": "0000003100016940830728",
"account_number_alias": "For testing",
"beneficiary_last_name": "Shepel",
"beneficiary_first_name": "Kristina",
"beneficiary_email": "kikikris.work@gmail.com",
"beneficiary_phone": "+541127637454",
"beneficiary_document_type": "nin",
"beneficiary_document_value": "96437418"
},
"extra": [
{
"key": "key_1",
"value": "value"
},
{
"key": "key_2",
"value": "value"
}
],
"timestamp": "2025-10-13T09:17:10.4744497Z",
"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": ""
}
Duplicated reference
{
"error_code": 108,
"error_reason": "Duplicated reference",
"request_id": "3829f5bd-6dcb-41f9-a4ba-3ff8b65a3cfc",
"reference": "",
"timestamp": "2025-11-10T08:47:22.81Z"
}
'bank_transfer_africa' missing field
{
"error_code": 31,
"error_reason": "Required fields are missing: bank_transfer_africa",
"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"
}
Callback Notifications
The system sends an HTTP callback to the callback_url of your request when a transaction reaches a final state. Always verify the callback signature; see Callback Verification.
Callback Payload
Callback request
{
"request_id": "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6",
"identifier": "PT_AFR_X1Y2Z3A4B5",
"reference": "AFR-ORD-2023-001",
"creation_date": "2023-11-21T14:50:15.123456",
"method": "bank_transfer_africa",
"type": "payout",
"mode": "initial",
"status": "success",
"status_date": "2023-11-21T14:50:18.654321",
"amount": "15000.00",
"currency": "NGN",
"billing_amount": "15000.00",
"billing_currency": "NGN",
"fee_amount": "50.00",
"fee_currency": "NGN",
"customer": {
"identifier": "CUST-NG-98765",
"email": "bola.ahmed@example.com",
"first_name": "Bola",
"last_name": "Ahmed",
"phone": "2349012345678",
"country": "NG",
"city": "Abuja",
"address": "123 Aso Rock Villa Road",
"zip_code": "900001",
"birthday": "1985-04-10",
"ip": "197.210.52.10"
},
"bank_transfer": {
"account_number": "0123456789",
"bank_code": "058",
"beneficiary_first_name": "Bola",
"beneficiary_last_name": "Ahmed",
"beneficiary_email": "bola.ahmed@example.com"
},
"error_code": 0,
"error_reason": "",
"timestamp": "2023-11-21T14:50:20.789012"
}