✓
Upgrade your plan
You'll be charged after confirming. Cancel anytime.
🔒 Secured by Stripe. Your card info never touches our servers.
AP
AfriPay
Welcome back
Sign in to your developer dashboard
By continuing you agree to AfriPay's Terms of Service
AP
AfriPay
v1.0 · STABLE
Overview
API
Networks
Account
user@example.com
PRO
4,231 / 50,000 calls
Dashboard
afripay / overview
LIVE
Requests Today
0
↑ 12% from yesterday
Avg Latency
312ms
Target: <400ms
Success Rate
98.7%
Last 24 hours
Errors Today
54
↓ 3 from yesterday
API Key copy
afp_live_••••••••••••••••••••••••
🔒 HMAC-signed 📅 Created Mar 1, 2026 🌍 KE · UG · GH · TZ · NG ⚡ Pro tier
Recent Transactions
Provider Status
M-PESA
● LIVE
MTN MOMO
● LIVE
AIRTEL
● DEGRADED
SNIPE
● LIVE
API Explorer — All Endpoints
POST /v1/pay Initiate payment · auto-detect network
GET /v1/status/:id Poll transaction status
POST /v1/disburse Send money to a phone number
GET /v1/balance All provider wallet balances
POST /v1/webhooks/{provider} Incoming callbacks (public)
GET /v1/keys/me API key info & tier
GET /health Server + provider health check
cURL
Node.js
Python
PHP

        
Try It Live — Sandbox Mode
ℹ️ Requests below are simulated in sandbox mode. No real money moves.
POST /v1/pay
sandbox
Response will appear here…
Test Phone Numbers
KE +254712345678 M-Pesa Kenya — success
UG +256771234567 MTN Uganda — success
GH +233241234567 MTN Ghana — success
FAIL +254731234567 Airtel Kenya — insufficient funds
Webhooks Configuration
Webhook Endpoints
POST https://api.afripay.dev/v1/webhooks/mpesa M-Pesa callbacks
POST https://api.afripay.dev/v1/webhooks/mtn MTN MoMo callbacks
POST https://api.afripay.dev/v1/webhooks/airtel Airtel Money callbacks
POST https://api.afripay.dev/v1/webhooks/snipe Snipe callbacks
Verify Webhook Signatures
// Verify AfriPay webhook signature in Node.js
const crypto = require('crypto');

function verifyWebhook(payload, secret, receivedSig, timestamp) {
  const message = `${timestamp}.${payload}`;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(receivedSig), Buffer.from(expected)
  );
}
Supported Mobile Money Networks
MP
M-Pesa
Kenya · Tanzania (Vodacom)
STK Push B2C Daraja v2
MTN
MTN MoMo
Uganda · Ghana · Rwanda · Zambia · 17 countries
Collect Disbursement MoMo API v1
AIR
Airtel Money
Kenya · Uganda · Tanzania · Ghana · Nigeria
USSD Push Disburse Airtel API v2
SNP
Snipe
Pan-African · Card · Mobile Money · USSD
Collect Disburse Snipe v1
Phone Number Auto-Detection

AfriPay detects the network from the phone prefix automatically. Pass "network":"auto" (default) and we handle routing.

PrefixCountryNetworkCurrency
+25470/71/72/79KenyaM-PesaKES
+25473/74KenyaAirtelKES
+25677/78/76UgandaMTN MoMoUGX
+25670/75UgandaAirtelUGX
+23324/25/26GhanaMTN MoMoGHS
+25574/75/76TanzaniaM-Pesa (Vodacom)TZS
+23480/81NigeriaAirtelNGN
Request Logs last 50 requests
Billing Overview
Current Plan
PRO
$79 / month · renews Apr 1, 2026
API Calls This Month
4,231
of 50,000 included (8.5%)
Next Invoice
$79.00
Due April 1, 2026
Payment Method
•••• 4242
Visa · expires 12/27
Invoice History
Mar 1, 2026 INV-2026-003 Pro Plan $79.00 PAID
Feb 1, 2026 INV-2026-002 Pro Plan $79.00 PAID
Jan 1, 2026 INV-2026-001 Starter Plan $19.00 PAID
Plans & Pricing
Free
$0/mo
500 calls/month
  • Sandbox access
  • M-Pesa (Kenya)
  • Basic documentation
  • Community support
  • Live payments
  • Disbursements
  • Webhooks
Starter
$19/mo
5,000 calls/month
  • Live payments
  • M-Pesa + MTN + Airtel
  • Webhooks
  • Email support
  • 3 countries
  • Disbursements
  • SLA guarantee
POPULAR
Pro
$79/mo
50,000 calls/month
  • Everything in Starter
  • All 4 networks + Snipe
  • 7 countries
  • Disbursements
  • Balance checks
  • Priority support
  • SLA guarantee
Ultra
$249/mo
Unlimited calls
  • Everything in Pro
  • All 17+ countries
  • 99.9% SLA guarantee
  • Custom webhooks
  • Dedicated Slack support
  • Custom rate limits
  • Invoice billing
💳 All plans are billed monthly. Cancel anytime. Payments processed securely by Stripe.
Getting Started
Introduction Quick Start Authentication
API Reference
POST /v1/pay GET /v1/status POST /v1/disburse GET /v1/balance Webhooks
Guides
Networks & Detection Error Codes Rate Limits Testing

AfriPay API Documentation

AfriPay is a unified mobile money API that lets you accept and send payments across Africa with a single integration. One API key, one request format — M-Pesa, MTN MoMo, Airtel Money, and Snipe all handled for you.

✓ Base URL: https://api.afripay.dev · Self-hosted: http://localhost:3000

Quick Start

Get your first payment running in under 5 minutes.

Step 1 — Get your API key

Go to the Dashboard, copy your API key, and add it to your environment:

# .env
AFRIPAY_KEY=afp_live_your_key_here

Step 2 — Install the SDK (optional)

# Node.js
npm install afripay

# Python
pip install afripay

# Or use the REST API directly — no SDK needed

Step 3 — Initiate your first payment

# cURL example — request an M-Pesa STK push
curl -X POST http://localhost:3000/v1/pay \
  -H "Authorization: Bearer afp_live_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "phone":     "+254712345678",
    "amount":    500,
    "currency":  "KES",
    "reference": "ORDER-001",
    "description": "Payment for Order #001"
  }'

Step 4 — Handle the webhook callback

AfriPay sends a callback to your callback_url when the payment completes or fails. Register your endpoint and verify the signature:

// Express.js webhook handler
app.post('/payments/callback', (req, res) => {
  const { transaction_id, status, network } = req.body;

  if (status === 'completed') {
    // ✓ Fulfil order, send receipt
    fulfillOrder(transaction_id);
  } else if (status === 'failed') {
    // ✕ Notify customer, retry or refund
    handleFailure(transaction_id);
  }

  res.sendStatus(200); // Always ACK
});

Authentication

All authenticated endpoints require your API key in the Authorization header as a Bearer token:

Authorization: Bearer afp_live_your_key_here
⚠️ Never expose your API key in client-side code or public repositories. Rotate compromised keys immediately from the Dashboard.

Key format

AfriPay keys follow this format: afp_{tier}_{32-char-hmac-signed-token}

PrefixTier
afp_free_Free
afp_start_Starter
afp_pro_Pro
afp_ultra_Ultra

POST /v1/pay

Initiate a mobile money payment. AfriPay automatically detects the network from the phone prefix and routes to the correct provider.

Request Parameters

ParameterTypeRequiredDescription
phonestringrequiredE.164 format e.g. +254712345678
amountnumberrequiredPositive number, max 150,000
currencystringoptionalISO 4217, e.g. KES. Auto-detected from phone if omitted.
referencestringrequiredYour order/transaction ref, max 20 chars
descriptionstringoptionalShown to customer, max 100 chars
callback_urlstringoptionalHTTPS URL for payment status callbacks
networkstringoptionalmpesa · mtn_momo · airtel · snipe · auto (default)

Response

{ "success": true, "transaction_id": "afp_a3f9b2c1d4e5", // AfriPay ID — use for status checks "provider_ref": "ws_CO_260320261234", // Provider's own reference "status": "pending", "network": "mpesa", "phone": "254712345678", "amount": 500, "currency": "KES", "country": "Kenya", "message": "Customer will receive a prompt on their phone.", "check_status": "GET /v1/status/afp_a3f9b2c1d4e5" }

GET /v1/status/:id

Poll the status of a transaction using its transaction_id returned from /v1/pay or /v1/disburse.

Path Parameters

ParameterTypeDescription
idstringAfriPay transaction ID starting with afp_

Status Values

StatusMeaning
pendingAwaiting customer action or provider confirmation
completedPayment successful — safe to fulfil order
failedPayment failed — check failure_reason
cancelledCustomer declined or timed out

POST /v1/disburse

Send money from your business wallet to a mobile money number. Requires Starter plan or above.

Request Parameters

ParameterTypeRequiredDescription
phonestringrequiredRecipient phone in E.164 format
amountnumberrequiredAmount to send, max 500,000
currencystringoptionalAuto-detected if omitted
referencestringrequiredYour internal reference
descriptionstringoptionalReason for payment

GET /v1/balance

Returns your current available balance across all configured provider wallets. Requires Pro plan or above.

{ "success": true, "balances": { "mpesa": { "available": 125000, "currency": "KES", "status": "ok" }, "mtn_momo": { "available": 450000, "currency": "UGX", "status": "ok" }, "airtel": { "status": "error", "reason": "unavailable" } } }

Webhooks

AfriPay sends a POST request to your callback_url when a transaction status changes. Always respond with HTTP 200 to acknowledge.

Webhook Payload

{ "event": "payment.completed", "transaction_id": "afp_a3f9b2c1d4e5", "status": "completed", "network": "mpesa", "amount": 500, "currency": "KES", "timestamp": "2026-03-26T09:15:00Z" }
⚠️ Always verify the X-AfriPay-Signature header before processing webhooks. See the Webhooks page for verification code.

Networks & Auto-Detection

AfriPay automatically detects the correct payment network from the phone number prefix using Rust-powered pattern matching. You never need to specify the network manually.

See the full prefix table on the Networks page.

Error Codes

CodeHTTPMeaning
VALIDATION_ERROR400Request body failed validation
INVALID_PHONE400Phone prefix not recognised
MISSING_API_KEY401Authorization header missing
INVALID_API_KEY401Key is malformed or tampered
FORBIDDEN403Transaction belongs to another key
TRANSACTION_NOT_FOUND404No transaction with that ID
RATE_LIMIT_EXCEEDED429Too many requests — check tier limits
INSUFFICIENT_FUNDS422Customer wallet is empty
PAYMENT_CANCELLED422Customer dismissed the prompt
PROVIDER_TIMEOUT504Provider didn't respond in time
PROVIDER_ERROR502Upstream provider returned an error
INTERNAL_ERROR500AfriPay internal error

Rate Limits

PlanRequests / 15 minMonthly calls
Free100500
Starter5005,000
Pro2,00050,000
Ultra10,000Unlimited

Rate limit headers are included in every response: RateLimit-Remaining, RateLimit-Reset.

Testing

Set MPESA_ENV=sandbox, MTN_MOMO_ENV=sandbox, and AIRTEL_ENV=sandbox in your .env file to use sandbox mode.

Running the test suite

# Install deps and run all tests
cd afripay/node-api
npm install
npm test

# With coverage
npm run test:coverage

Test phone numbers

Use these numbers in sandbox mode to trigger specific outcomes. Visit the Try It Live page to test interactively.

PhoneNetworkResult
+254712345678M-Pesa KESuccess
+256771234567MTN UgandaSuccess
+233241234567MTN GhanaSuccess
+254731234567Airtel KEInsufficient funds