recipient payload to match your payout use case, or browse the dedicated payout examples for a full walkthrough.
Endpoint
POSThttps://sandboxapi.me-cash.com/v2/payout
Environment Note: The endpoint above is for Sandbox testing. In Production, replace
sandboxapi with api (https://api.me-cash.com/v2/payout).You must supply the quoteId generated by the Create Quote API. Quotes that have expired or already been consumed will be rejected.Request headers
| Header | Description | Required | Example |
|---|---|---|---|
x-api-key | Workspace API key for authentication. | ✅ Yes | YOUR_API_KEY |
Content-Type | Media type of the request body. | ✅ Yes | application/json |
Request body
copy
{
"recipient": {
"name": "Chris Tiana",
"paymentChannel": "BANK_TRANSFER",
"country": "NG",
"stored": false,
"account": {
"bankName": "Guaranty Trust Bank",
"sortCode": "058",
"accountNumber": "0712617XXX"
}
},
"quoteId": "453eeu-567j-6tr3d-xxxxxxxxxxxxx",
"reason": "Bills",
"invoice": "4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx",
"remark": ""
}
Body fields
| Field | Type | Description | Required | Example |
|---|---|---|---|---|
recipient.name | String | Full name of the beneficiary. | ✅ Yes | Chris Tiana |
recipient.paymentChannel | String | Channel to deliver funds (BANK_TRANSFER, MOBILE_MONEY, SWIFT_CUSTOMER, SWIFT_SHARED, SWIFT_BENEFICIARY). | ✅ Yes | BANK_TRANSFER |
recipient.country | String | Recipient country (ISO 3166-1 alpha-2). | ✅ Yes | NG |
recipient.stored | Boolean | Whether the recipient is saved in your address book. | ✅ Yes | false |
recipient.account.bankName | String | Financial institution name. | ✅ Yes | Guaranty Trust Bank |
recipient.account.sortCode | String | Routing or sort code where applicable. | ✅ Yes | 058 |
recipient.account.accountNumber | String | Destination account number. | ✅ Yes | 0712617XXX |
quoteId | String | Quote identifier returned from the Quote API. | ✅ Yes | 453eeu-567j-6tr3d-xxxxxxxxxxxxx |
reason | String | High-level purpose of the transfer. | ✅ Yes | Bills |
invoice | String | Optional identifier for the invoice (returned from file upload endpoint). | ❌ No | 4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx |
remark | String | Additional comments or reference. | Optional | September utilities |
payout docs examples.
Request examples
curl --request POST 'https://sandboxapi.me-cash.com/v2/payout' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"recipient": {
"name": "Chris Tiana",
"paymentChannel": "BANK_TRANSFER",
"country": "NG",
"stored": false,
"account": {
"bankName": "Guaranty Trust Bank",
"sortCode": "058",
"accountNumber": "0712617XXX"
}
},
"quoteId": "453eeu-567j-6tr3d-xxxxxxxxxxxxx",
"reason": "Bills",
"invoice": "4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx",
"remark": ""
}'
const payload = {
recipient: {
name: 'Chris Tiana',
paymentChannel: 'BANK_TRANSFER',
country: 'NG',
stored: false,
account: {
bankName: 'Guaranty Trust Bank',
sortCode: '058',
accountNumber: '0712617XXX'
}
},
quoteId: '453eeu-567j-6tr3d-xxxxxxxxxxxxx',
reason: 'Bills',
invoice: '4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx',
remark: ''
};
fetch('https://sandboxapi.me-cash.com/v2/payout', {
method: 'POST',
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
})
.then((res) => {
if (!res.ok) {
throw new Error(`Request failed with status ${res.status}`);
}
return res.json();
})
.then((body) => console.log(body))
.catch((error) => console.error('Failed to create payout', error));
import requests
url = "https://sandboxapi.me-cash.com/v2/payout"
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
}
payload = {
"recipient": {
"name": "Chris Tiana",
"paymentChannel": "BANK_TRANSFER",
"country": "NG",
"stored": False,
"account": {
"bankName": "Guaranty Trust Bank",
"sortCode": "058",
"accountNumber": "0712617XXX",
},
},
"quoteId": "453eeu-567j-6tr3d-xxxxxxxxxxxxx",
"reason": "Bills",
"invoice": "4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx",
"remark": "",
}
response = requests.post(url, json=payload, headers=headers, timeout=30)
response.raise_for_status()
print(response.json())
const axios = require('axios');
axios.post('https://sandboxapi.me-cash.com/v2/payout', {
recipient: {
name: 'Chris Tiana',
paymentChannel: 'BANK_TRANSFER',
country: 'NG',
stored: false,
account: {
bankName: 'Guaranty Trust Bank',
sortCode: '058',
accountNumber: '0712617XXX'
}
},
quoteId: '453eeu-567j-6tr3d-xxxxxxxxxxxxx',
reason: 'Bills',
invoice: '4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx',
remark: ''
}, {
headers: {
'x-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
timeout: 30000
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
if (error.response) {
console.error('API error:', error.response.data);
} else {
console.error('Request error:', error.message);
}
});
Successful response
copy
{
"message": "payout queued",
"status": "success",
"data": {
"id": "f4e597cc-18fa-4c23-b9c1-xxxxxxxxxxxxx",
"invoice": "4b9b6d30-a2ed-421a-bd69-xxxxxxxxxxxx",
"reference": "BILLS-20240915",
"quoteId": "453eeu-567j-6tr3d-xxxxxxxxxxxxx",
"state": "PROCESSING",
"recipient": {
"name": "Chris Tiana",
"country": "NG",
"paymentChannel": "BANK_TRANSFER"
},
"metadata": {},
"created": "2024-09-15T10:32:11.238Z"
}
}
Field reference
| Field | Type | Description |
|---|---|---|
data.id | String | Unique payout identifier returned by meCash. |
data.invoice | String | Optional identifier for the invoice provided in the request. |
data.reference | String | Your client-generated reference if supplied. |
data.state | String | Initial processing state (PROCESSING, QUEUED, etc.). |
data.recipient | Object | Echoes key beneficiary attributes. |
data.created | String | ISO timestamp for when the payout was accepted. |
Error responses
| Status | Message | Cause | How to resolve |
|---|---|---|---|
| 400 | Insufficient wallet balance for transaction | Wallet balance cannot cover the payout amount. | Top up the wallet or lower the payout total before retrying. |
| 400 | Quotes only last for 10 minutes | Quote expired before you attempted to consume it. | Generate a fresh quote and submit the payout immediately. |
| 400 | Invalid country or currency ISO code | Unsupported country/currency combination supplied in the request. | Use corridor-supported ISO codes for both quote and recipient data. |
| 400 | Account name mismatch, use account enquiry endpoint | Account name in payload differs from bank enquiry results. | Re-run account enquiry and match the returned account name. |
| 400 | Invalid Bank Sortcode | Sort code missing, malformed, or unsupported. | Fetch the correct sort code from the bank list and verify formatting. |
| 400 | {field_name} cannot be empty | Required recipient field omitted from the payload. | Fill in every mandatory field (name, account number, etc.) before submitting. |
| 401 | API key missing or incorrect | x-api-key header absent, invalid, or expired. | Supply the correct API key for the environment you are targeting. |
| 403 | IP not whitelisted | Request originated from an unapproved IP. | Add your server IP to the dashboard allowlist. |
| 404 | The requested endpoint does not exist | Incorrect API path or version specified. | Confirm you are calling POST /v2/payout on the right base URL. |
| 422 | Invalid quote ID provided | Quote ID missing, invalid, expired, or already consumed. | Create a new quote and reference it in the payout call. |
| 500 | Service temporarily unavailable | Temporary backend/service disruption. | Retry with exponential backoff; contact support if it persists. |
Best practices
- Generate idempotency references to safely retry without duplicating transfers.
- Validate recipients locally before calling the API to reduce error handling.
- Listen to payout webhooks and reconcile with the
Get Transaction APIfor final settlement details. - Need to pay multiple recipients at once? Use the Bulk Payout API instead.
Testing Failed Payouts: In the sandbox environment, you can simulate a failed payout by setting
"remark": "fail" in your request. This will trigger a payout.failed webhook, allowing you to test your error handling logic.
