AbomaxPay API Documentation

Welcome to the AbomaxPay API — a payment gateway that lets you accept and send payments via Mobile Money across Uganda and Kenya.

Base URL

// All API requests
https://api.abomaxpay.com/v1

Supported Countries

CountryCurrencyCollection MethodsPayout Methods
Uganda flagUgandaUGXMTN, AirtelMTN, Airtel
Kenya flagKenyaKESSafaricom (M-Pesa), AirtelSafaricom, Airtel

Quickstart

Go from signup to your first test payment in five steps.

  1. Create an account on the dashboard and complete onboarding.
  2. Generate API keys on the Developers page. Use sk-test- keys while testing.
  3. Fund your wallet via the dashboard wallet page — in test mode, funding is simulated instantly.
  4. Process a collection with a test phone number to send a test USSD prompt.
  5. Verify the outcome via /collect/verify or a webhook before delivering goods.

Minimal Example — Process a Collection

cURL

curl -X POST https://api.abomaxpay.com/v1/collect \
  -H "Authorization: Bearer sk-test-xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"amount": 50000, "currency": "UGX", "phone": "256772345678", "email": "customer@example.com", "first_name": "Mukasa", "last_name": "Okello", "provider_code": "MTNUGA"}'

PHP

$ch = curl_init('https://api.abomaxpay.com/v1/collect');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer sk-test-xxxxxxxxxxxxxxxx', 'Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['amount' => 50000, 'currency' => 'UGX', 'phone' => '256772345678', 'email' => 'customer@example.com', 'first_name' => 'Mukasa', 'last_name' => 'Okello', 'provider_code' => 'MTNUGA']));
$response = curl_exec($ch);
curl_close($ch);

Python

import requests

resp = requests.post(
  'https://api.abomaxpay.com/v1/collect',
  headers={'Authorization': 'Bearer sk-test-xxxxxxxxxxxxxxxx'},
  json={
    'amount': 50000,
    'currency': 'UGX',
    'phone': '256772345678',
    'email': 'customer@example.com',
    'first_name': 'Mukasa',
    'last_name': 'Okello',
    'provider_code': 'MTNUGA'
  }
)
print(resp.json())
You're done. The response returns a reference with status pending. Always confirm the final outcome via webhook or /collect/verify before fulfilling the order.

Authentication

All API requests require your secret API key. Find your keys on the Developers page.

Security: Never expose your secret key in client-side code. Use it only on your backend server.

Request Headers

Authorization: Bearer sk-test-xxxxxxxxxxxxxxxx
Content-Type: application/json

Test Mode

Use test API keys (prefixed sk-test-) to simulate transactions without real money.

Fully simulated: In test mode, AbomaxPay simulates the entire payment flow locally — no real Mobile Money or Payaza sandbox is contacted. Initiate a collection to get a pending reference, then confirm the outcome via /collect/verify or a webhook exactly as you would in production.

Test Phone Numbers

CountryTest NumberExpected Result
Uganda (MTN)256770000001Success
Uganda (Airtel)256750000001Success
Kenya (Safaricom)254700000001Success
Any countryAny number ending in 0000Failed (declined)
Test PIN: Use 0000 for all test Mobile Money transactions. No real money is deducted.
Live mode: Live API keys only process real money once your account is KYC-verified. Until then, requests made with a sk-live- key are automatically downgraded to test mode.

Error Handling

Every API response includes an error_code integer field. Use this code to handle errors programmatically — HTTP status codes follow standard conventions, while error_code identifies the specific AbomaxPay error.

Response Format

// Success
{
  "success": true,
  "message": "Collection initiated",
  "error_code": 0,
  "data": { ... }
}

// Error
{
  "success": false,
  "message": "Insufficient UGX balance",
  "error_code": 4003
}

Error Code Ranges

RangeCategoryDescription
0SuccessRequest completed successfully
1000 – 1999AuthAuthentication, API key, or PIN errors
2000 – 2999ValidationMissing/invalid request parameters
3000 – 3999CollectionsPayment collection errors
4000 – 4999PayoutsPayout/withdrawal errors
5000 – 5999WalletWallet or account errors
9000 – 9999SystemInternal, maintenance, or upstream errors
Pending is Normal: Status pending means the USSD prompt was sent. Always verify final status via webhook or /collect/verify before delivering goods.

Error Codes Reference

Complete list of all error_code values returned by the API.

Authentication & Authorization

CodeMessageHTTP
1001Missing Authorization header401
1002Invalid Authorization header format401
1003Invalid API key401
1004Merchant account is not active403
1005Invalid transaction PIN400
1006Transaction PIN not set400

Validation & Input

CodeMessageHTTP
2001Invalid JSON body400
2002Missing required field400
2003Invalid amount400
2004Amount too low400
2005Invalid currency400
2006Invalid phone number400
2007Invalid email address400
2008Invalid provider code400
2009Invalid transaction reference400
2010Method not allowed405
2011Amount too high400
2013Payout threshold not met400

Collections

CodeMessageHTTP
3001Collection failed502
3004Collection not found404

Payouts

CodeMessageHTTP
4003Insufficient balance400
4004Payout not found404

Wallet & Account

CodeMessageHTTP
5001Wallet not found404

System

CodeMessageHTTP
9001Internal server error500
9003Rate limited429
9004Endpoint not found404
9005API under maintenance503
9006Deposits disabled403
9007Payouts disabled403

How Collections Work

  1. Your server calls Process Collection with the customer's phone number and amount.
  2. AbomaxPay sends a USSD prompt to the customer's phone: "Approve payment of [amount]?"
  3. Customer enters their Mobile Money PIN to approve.
  4. Confirm final outcome via webhook or status check.

Process Collection

Initiate a payment from your customer.

POST https://api.abomaxpay.com/v1/collect

Examples by Country

Uganda — MTN Mobile Money

const response = await fetch('https://api.abomaxpay.com/v1/collect', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk-test-xxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    amount: 50000,
    currency: 'UGX',
    phone: '256772345678',
    email: 'customer@example.com',
    first_name: 'Mukasa',
    last_name: 'Okello',
    provider_code: 'MTNUGA',
    narration: 'Invoice payment'
  })
});

Kenya — Safaricom M-Pesa

{
  amount: 1000,
  currency: 'KES',
  phone: '254712345678',
  email: 'mwangi@example.com',
  first_name: 'John',
  last_name: 'Mwangi',
  provider_code: 'SAFKEN',
  narration: 'M-Pesa payment'
}

Request Parameters

ParameterTypeRequiredDescription
amountnumberRequiredAmount to collect. Min: UGX 100 / KES 3.5. Max per single deposit: UGX 5,000,000 / KES 172,238.94.
currencystringOptionalUGX (default) or KES
phonestringRequiredInternational format with country code
emailstringOptionalCustomer email address
first_namestringOptionalCustomer first name (only if known)
last_namestringOptionalCustomer last name (only if known)
provider_codestringRequiredMTNUGA, AIRUGA (UG) or SAFKEN, AIRKEN (KE)
narrationstringOptionalPayment description (default: "Payment")
merchant_referencestringOptionalYour own reference to attach to this transaction (max 255 chars). Echoed back in the response and in collection.pending webhooks. Accepted aliases: reference, client_reference, external_reference.

Response (Pending)

{
  "success": true,
  "message": "Collection initiated",
  "error_code": 0,
  "data": {
    "reference": "ABX26071234567",
    "status": "pending",
    "amount": 50000,
    "fee": 2250,
    "provider_fee": 1500,
    "gateway_margin": 750,
    "net_amount": 47750,
    "currency": "UGX",
    "transaction_id": 42,
    "merchant_reference": "order-12345"
  }
}
merchant_reference is only included in the response when you pass it in the request. The response always includes the full fee breakdown (provider_fee, gateway_margin, net_amount).

Verify Payment

GET https://api.abomaxpay.com/v1/collect/verify/{reference}

const status = await fetch('https://api.abomaxpay.com/v1/collect/verify/ABX26071234567', {
  headers: { 'Authorization': 'Bearer sk-test-xxxxxxxxxxxxxxxx' }
});

// Completed response:
{
  "success": true,
  "message": "Transaction retrieved",
  "error_code": 0,
  "data": {
    "reference": "ABX26071234567",
    "amount": 50000,
    "fee": 2250,
    "net_amount": 47750,
    "currency": "UGX",
    "status": "completed",
    "narration": "Payment",
    "phone": "256772345678",
    "provider_code": "MTNUGA",
    "created_at": "2026-07-08T10:30:00Z",
    "updated_at": "2026-07-08T10:30:29Z"
  }
}

Transaction Statuses

StatusMeaning
pendingAwaiting customer approval
completedPayment successful — funds received
failedPayment declined or timed out

Phone Number Formats

CountryFormatDigitsExample
Uganda256 + number12256772345678
Kenya254 + number12254712345678

Provider Code Reference

CountryNetworkProvider Code
UgandaMTNMTNUGA
UgandaAirtelAIRUGA
KenyaSafaricomSAFKEN
KenyaAirtelAIRKEN

Payout Overview — Send Money

Send funds from your AbomaxPay wallet to any Mobile Money wallet in Uganda and Kenya.

Requirements:
• Your AbomaxPay wallet must have sufficient balance
• Set your 6-digit transaction PIN in dashboard settings
• Transaction reference is auto-generated (format: abx + 27 random alphanumeric chars)

Payout Flow

  1. Initiate Payout with recipient details and your PIN
  2. Verify Outcome via webhook or status check

Step 2 — Initiate Payout

Send funds to a Mobile Money wallet in Uganda and Kenya.

POST https://api.abomaxpay.com/v1/withdraw

Examples by Country

Uganda — Send to MTN Mobile Money

{
  amount: 100000,
  currency: 'UGX',
  phone: '256772345678',
  account_name: 'Mukasa Okello',
  provider_code: 'MTNUGA',
  narration: 'Business payout',
  pin: '123456'
}

Kenya — Send to M-Pesa

{
  amount: 5000,
  currency: 'KES',
  phone: '254712345678',
  account_name: 'John Mwangi',
  provider_code: 'SAFKEN',
  narration: 'Contractor payment',
  pin: '123456'
}

Request Parameters

ParameterTypeRequiredDescription
amountnumberRequiredAmount to send
currencystringOptionalUGX (default) or KES
phonestringRequiredRecipient phone with country code
account_namestringRequiredRecipient's full name
provider_codestringRequiredMTNUGA, AIRUGA (UG) or SAFKEN, AIRKEN (KE)
narrationstringOptionalDescription (max 25 chars, alphanumeric only)
pinstringRequiredYour transaction PIN

Success Response

{
  "success": true,
  "message": "Payout initiated",
  "error_code": 0,
  "data": {
    "reference": "ABX26071234567",
    "status": "pending",
    "amount": 100000,
    "fee": 4500,
    "net_amount": 95500,
    "currency": "UGX"
  }
}

Step 3 — Verify Payout

GET https://api.abomaxpay.com/v1/withdraw/verify/{reference}

const status = await fetch('https://api.abomaxpay.com/v1/withdraw/verify/ABX26071234567', {
   headers: { 'Authorization': 'Bearer sk-test-xxxxxxxxxxxxxxxx' }
});

// Completed response:
{
  "success": true,
  "message": "Transaction retrieved",
  "error_code": 0,
  "data": {
    "reference": "ABX26071234567",
    "amount": 100000,
    "fee": 4500,
    "net_amount": 95500,
    "currency": "UGX",
    "status": "completed",
    "narration": "Business payout",
    "phone": "256772345678",
    "provider_code": "MTNUGA",
    "created_at": "2026-07-08T14:45:00Z",
    "updated_at": "2026-07-08T14:45:30Z"
  }
}

Payout Statuses

StatusMeaning
pendingPayout initiated, awaiting processing
completedPayout completed — funds delivered
failedPayout failed — funds returned to wallet
Important:
• Generate a unique reference for every payout — never reuse
• Payouts are final and cannot be reversed
• Double-check account number before submitting
• Keep your transaction PIN secure

Wallet Balance

Retrieve the current balance of all your wallets. Balances are updated when a collection completes or a payout is initiated.

GET https://api.abomaxpay.com/v1/balance

const balance = await fetch('https://api.abomaxpay.com/v1/balance', {
  headers: { 'Authorization': 'Bearer sk-test-xxxxxxxxxxxxxxxx' }
});

Success Response

{
  "success": true,
  "message": "Balances retrieved",
  "error_code": 0,
  "data": {
    "wallets": [
      { "currency": "UGX", "balance": 250000, "status": "active" },
      { "currency": "KES", "balance": 0, "status": "active" }
    ]
  }
}
One wallet is returned per supported currency. Check your wallet balance before initiating payouts to avoid insufficient-balance errors.

Webhooks

Receive real-time notifications for payment and payout events. Configure your webhook URL on the Developers page.

Events

EventWhen It Fires
collection.pendingCollection initiated — USSD prompt sent to customer
collection.successCollection successful — funds received
collection.failedCollection failed, declined, or timed out
payout.pendingPayout initiated — awaiting processing
payout.successPayout successful — funds delivered
payout.failedPayout failed — funds returned to wallet

Collection Webhook Payloads

collection.pending

{
  "event": "collection.pending",
  "reference": "ABX26071234567",
  "amount": 50000,
  "fee": 2250,
  "net_amount": 47750,
  "currency": "UGX",
  "status": "pending",
  "transaction_id": 42,
  "merchant_reference": "order-12345",
  "created_at": "2026-07-08T10:30:00Z"
}

collection.success

{
  "event": "collection.success",
  "reference": "ABX26071234567",
  "amount": 50000,
  "fee": 2250,
  "net_amount": 47750,
  "currency": "UGX",
  "status": "completed",
  "created_at": "2026-07-08T10:30:00Z"
}

collection.failed

{
  "event": "collection.failed",
  "reference": "ABX26071234567",
  "amount": 50000,
  "currency": "UGX",
  "status": "failed",
  "created_at": "2026-07-08T10:30:00Z"
}

Payout Webhook Payloads

Note: When a payout fails during status verification, the fee and net_amount fields may be absent from the payload. Always check for these fields before using them.

payout.success

{
  "event": "payout.success",
  "reference": "ABX26071234567",
  "amount": 100000,
  "fee": 4500,
  "net_amount": 95500,
  "currency": "UGX",
  "status": "completed",
  "account_name": "Mukasa Okello",
  "phone": "256772345678",
  "provider_code": "MTNUGA",
  "created_at": "2026-07-08T14:45:00Z"
}

Verify Webhook Signature

Every webhook request includes an x-abomax-signature header containing an HMAC-SHA256 hash of the request body signed with your webhook secret.

Critical: Compute the signature over the exact raw request body string as received — never re-serialize a parsed JSON object (e.g., JSON.stringify(req.body)), as key ordering or whitespace changes will make the signature mismatch.
const crypto = require('crypto');

// Capture the RAW body as a string BEFORE any JSON parsing
let rawBody = '';
req.on('data', chunk => { rawBody += chunk; });
req.on('end', () => {
  const signature = req.headers['x-abomax-signature'];
  const expected = 'sha256=' + crypto
    .createHmac('sha256', 'YOUR_WEBHOOK_SECRET')
    .update(rawBody)
    .digest('hex');

  if (signature === expected) {
    // Webhook is authentic — now parse and process the event
  }
});

// Express users: expose the raw body via express.json({ verify: (req, res, buf) => { req.rawBody = buf; } })

Other headers:

HeaderDescription
x-abomax-signatureHMAC-SHA256 signature (format: sha256=<hex>)
x-abomax-eventEvent type (e.g., collection.success)
x-abomax-modetest or live

Changelog

v1.0.0 — July 2026