Disbursements API
Send money to recipients via mobile money networks.
Overview​
The Disbursements API allows you to send money directly to recipients' mobile money accounts. Currently supporting Airtel Money B2C in Tanzania.
Endpoint​
POST /payment-service/airtel/b2c
Authentication​
Requires Bearer token authentication:
Authorization: Bearer YOUR_API_TOKEN
Request Parameters​
Parameter | Type | Required | Description |
---|---|---|---|
phone_number | string | Yes | Recipient's phone number (E.164 format) |
amount | string | Yes | Amount to send (minimum 500 TZS) |
external_id | string | No | Your unique transaction reference |
Request Example​
{
"phone_number": "+255683542710",
"amount": "1000"
}
Response Example​
Success Response​
{
"status": "success",
"message": "Disbursement initiated successfully",
"transaction_id": "TXN_123456789",
"reference": "GCA_REF_987654321",
"amount": "1000",
"currency": "TZS",
"phone_number": "+255683542710",
"status_code": "PROCESSING"
}
Error Response​
{
"status": "error",
"message": "Insufficient funds in merchant account",
"error_code": "INSUFFICIENT_FUNDS"
}
Status Codes​
Code | Description |
---|---|
PROCESSING | Disbursement is being processed |
SUCCESS | Money sent successfully |
FAILED | Disbursement failed |
INSUFFICIENT_FUNDS | Merchant account has insufficient balance |
Implementation Example​
JavaScript/Node.js​
const axios = require('axios');
async function sendMoney(phoneNumber, amount) {
try {
const response = await axios.post(
'https://gcapay.site/api/v1/payment-service/airtel/b2c',
{
phone_number: phoneNumber,
amount: amount.toString()
},
{
headers: {
'Authorization': 'Bearer YOUR_API_TOKEN',
'Content-Type': 'application/json'
}
}
);
console.log('Disbursement initiated:', response.data);
return response.data;
} catch (error) {
console.error('Disbursement failed:', error.response?.data);
throw error;
}
}
// Usage
sendMoney('+255683542710', 1000);
Python​
import requests
def send_money(phone_number, amount):
url = "https://gcapay.site/api/v1/payment-service/airtel/b2c"
headers = {
"Authorization": "Bearer YOUR_API_TOKEN",
"Content-Type": "application/json"
}
payload = {
"phone_number": phone_number,
"amount": str(amount)
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Disbursement failed: {e}")
raise
# Usage
result = send_money("+255683542710", 1000)
print(result)
PHP​
<?php
function sendMoney($phoneNumber, $amount) {
$url = 'https://gcapay.site/api/v1/payment-service/airtel/b2c';
$data = array(
'phone_number' => $phoneNumber,
'amount' => (string)$amount
);
$headers = array(
'Authorization: Bearer YOUR_API_TOKEN',
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
return json_decode($response, true);
} else {
throw new Exception("Disbursement failed: " . $response);
}
}
// Usage
try {
$result = sendMoney('+255683542710', 1000);
echo json_encode($result, JSON_PRETTY_PRINT);
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
?>
Use Cases​
Salary Payments​
Send monthly salaries to employee mobile money accounts:
async function paySalaries(employees) {
const results = [];
for (const employee of employees) {
try {
const result = await sendMoney(employee.phone, employee.salary);
results.push({
employee: employee.name,
status: 'success',
transaction_id: result.transaction_id
});
} catch (error) {
results.push({
employee: employee.name,
status: 'failed',
error: error.message
});
}
// Rate limiting - wait 1 second between requests
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
Supplier Payments​
Pay suppliers and vendors instantly:
async function paySupplier(supplierId, amount, reference) {
const supplier = await getSupplierDetails(supplierId);
return await sendMoney(supplier.phone, amount, reference);
}
Customer Refunds​
Process customer refunds automatically:
async function processRefund(orderId) {
const order = await getOrderDetails(orderId);
if (order.status === 'cancelled') {
return await sendMoney(order.customer_phone, order.amount, `REFUND_${orderId}`);
}
}
Best Practices​
Balance Management​
- Check your account balance before large disbursements
- Set up balance alerts to avoid failed transactions
- Implement balance validation in your application
Rate Limiting​
- Implement delays between consecutive requests
- Maximum 10 requests per minute recommended
- Use queuing for bulk disbursements
Error Handling​
- Retry failed transactions with exponential backoff
- Log all transactions for audit trails
- Handle network timeouts gracefully
Security​
- Validate recipient phone numbers
- Implement approval workflows for large amounts
- Monitor for suspicious activity patterns
Account Balance​
Before making disbursements, ensure your merchant account has sufficient funds. You can check your balance through the merchant dashboard or contact support.
Insufficient Funds Error​
{
"status": "error",
"message": "Insufficient funds in merchant account",
"error_code": "INSUFFICIENT_FUNDS",
"available_balance": "500.00",
"requested_amount": "1000.00"
}
Testing​
Use the following test credentials in sandbox environment:
- Test Phone:
+255683542710
- Test Amount:
1000
- Expected Result: Success response
Transaction Limits​
Type | Minimum | Maximum |
---|---|---|
Single Transaction | 500 TZS | 1,000,000 TZS |
Daily Total | - | 10,000,000 TZS |
Monthly Total | - | 100,000,000 TZS |
Common Errors​
Error Code | Description | Solution |
---|---|---|
INSUFFICIENT_FUNDS | Not enough balance | Top up merchant account |
INVALID_PHONE_NUMBER | Wrong phone format | Use E.164 format |
AMOUNT_TOO_LOW | Below minimum amount | Use 500 TZS or higher |
RECIPIENT_NOT_FOUND | Phone number not registered | Verify phone number |
NETWORK_ERROR | Mobile network issue | Retry after few minutes |
Next Steps​
- Collections API → - Accept customer payments
- Webhooks → - Handle transaction status updates
- Transaction Inquiry → - Query transaction status