Skip to main content

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​

ParameterTypeRequiredDescription
phone_numberstringYesRecipient's phone number (E.164 format)
amountstringYesAmount to send (minimum 500 TZS)
external_idstringNoYour 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​

CodeDescription
PROCESSINGDisbursement is being processed
SUCCESSMoney sent successfully
FAILEDDisbursement failed
INSUFFICIENT_FUNDSMerchant 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​

TypeMinimumMaximum
Single Transaction500 TZS1,000,000 TZS
Daily Total-10,000,000 TZS
Monthly Total-100,000,000 TZS

Common Errors​

Error CodeDescriptionSolution
INSUFFICIENT_FUNDSNot enough balanceTop up merchant account
INVALID_PHONE_NUMBERWrong phone formatUse E.164 format
AMOUNT_TOO_LOWBelow minimum amountUse 500 TZS or higher
RECIPIENT_NOT_FOUNDPhone number not registeredVerify phone number
NETWORK_ERRORMobile network issueRetry after few minutes

Next Steps​