SamPay API
Build mobile money, card, and bill payments into your product.
Create payment prompts, process card payments, generate hosted checkout sessions, sell airtime, pay bills including ZESCO and DStv, track transaction status, and verify signed webhook events from one public developer reference.
curl -X POST https://payments.sampay.dev/api/v1/payments/initiate \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-API-Key: pk_your_api_key" \
-H "X-Timestamp: 1234567890" \
-H "X-Signature: generated_hmac_signature" \
-d '{
"reference": "ORD-12345",
"amount": 100.00,
"currency": "ZMW",
"payment_method": "mtn_momo",
"customer_phone": "260971234567"
}'
Quickstart
Get keys
Create or open a merchant account and copy the API key and secret key from the portal.
Sign requests
Generate an HMAC SHA-256 signature using your secret key, timestamp, and JSON payload.
Send payment
Initiate a direct mobile money prompt or redirect customers to hosted checkout.
Authentication
Protected API requests use your API key and an HMAC signature generated with your secret key.
Base URL
Required headers
Accept: application/json
Content-Type: application/json
X-API-Key: pk_your_api_key
X-Timestamp: 1234567890
X-Signature: generated_hmac_signature
PHP signature example
$timestamp = time();
$payload = json_encode($requestBody);
$signature = hash_hmac('sha256', $timestamp . $payload, $secretKey);
Direct initiate payment
Creates a transaction and sends a mobile money prompt to the customer phone number.
Request body
{
"reference": "ORD-12345",
"amount": 100.00,
"currency": "ZMW",
"payment_method": "mtn_momo",
"customer_phone": "260971234567",
"customer_email": "customer@example.com",
"customer_name": "John Doe",
"callback_url": "https://your-site.com/webhooks/payment",
"metadata": {
"order_id": "ORD-12345"
}
}
API list: Mobile Money collections, Card checkout, and Bill Payments for airtime, zesco, and dstv. Direct mobile money methods are mtn_momo, mtn, airtel_money, airtel, zamtel_kwacha, and zamtel.
Success response
{
"success": true,
"transaction_id": 12345,
"reference": "ORD-12345",
"status": "processing",
"amount": 100,
"currency": "ZMW",
"message": "Payment initiated successfully."
}
Hosted checkout initiate
Use hosted checkout when SamPay should collect the customer's wallet number or card details on a payment page.
Request body
{
"reference": "ORD-12346",
"amount": 100.00,
"currency": "ZMW",
"payment_method": "mobile_money_zm",
"customer_email": "customer@example.com",
"customer_name": "John Doe",
"callback_url": "https://your-site.com/webhooks/payment",
"success_url": "https://your-site.com/payment/success",
"failure_url": "https://your-site.com/payment/failed"
}
Use payment_method: "card" for card-only checkout, payment_method: "mobile_money_zm" for mobile-money-only checkout, or payment_method: "both" to show both options. Card details are entered only on the secure card payment page.
Success response
{
"success": true,
"transaction_id": 12346,
"reference": "ORD-12346",
"status": "pending",
"checkout_url": "https://example.com/checkout/ORD-12346?expires=..."
}
Check payment status
This request is signed. For an empty GET body, sign the timestamp plus an empty string.
Response
{
"success": true,
"reference": "ORD-12345",
"status": "completed",
"amount": 100,
"currency": "ZMW",
"completed_at": "2026-05-11T12:15:00.000000Z"
}
Bill payments and VAS
Merchants send a signed REST request to SamPay. SamPay validates the request, processes the bill payment, stores the transaction, and returns a merchant-friendly JSON response.
Supported services: airtime for MTN, Airtel, and Zamtel top-ups; zesco for electricity tokens; and dstv for DStv subscription payments.
Request body
{
"reference": "BILL-12345",
"service": "zesco",
"amount": 50.00,
"currency": "ZMW",
"account_number": "12345678901",
"customer_phone": "260971234567",
"callback_url": "https://your-site.com/webhooks/payment",
"metadata": {
"order_id": "ORDER-12345"
}
}
| Field | Description |
|---|---|
| reference | Required unique merchant reference. Duplicate references are rejected. |
| service | Required. One of airtime, zesco, or dstv. |
| network | Required for airtime only. One of mtn, airtel, or zamtel. |
| amount | Required decimal amount in Kwacha. |
| account_number | Required. Airtime phone number, ZESCO meter number, or DStv account/smartcard number. |
| callback_url | Optional per-transaction webhook URL. |
ZESCO token purchase
Use this for electricity token purchases. A successful payment returns voucher_pin_number as the token for the customer meter.
{
"reference": "ZESCO-12345",
"service": "zesco",
"amount": 50.00,
"currency": "ZMW",
"account_number": "12345678901"
}
Airtime top-up
Use this for MTN, Airtel, and Zamtel airtime top-ups. The recipient is the phone number receiving airtime.
{
"reference": "AIRTIME-12345",
"service": "airtime",
"network": "mtn",
"amount": 10.00,
"currency": "ZMW",
"account_number": "260971234567"
}
DStv payment
Use this for DStv subscription payments. The account number is the DStv account or smartcard number.
{
"reference": "DSTV-12345",
"service": "dstv",
"amount": 200.00,
"currency": "ZMW",
"account_number": "1234567890"
}
Success response
{
"success": true,
"message": "Bill payment processed successfully.",
"data": {
"reference": "ZESCO-12345",
"status": "completed",
"service": "zesco",
"amount": 50,
"fee": 1.25,
"total_debit": 51.25,
"currency": "ZMW",
"provider": "sampay",
"service_reference": "...",
"purchase_id": "...",
"voucher_pin_number": "1234 5678 9012 3456",
"voucher_serial_number": "..."
}
}
Status response
GET https://payments.sampay.dev/api/v1/bills/ZESCO-12345
{
"success": true,
"data": {
"reference": "ZESCO-12345",
"status": "completed",
"service": "zesco",
"amount": 50,
"fee": 1.25,
"total_debit": 51.25,
"currency": "ZMW",
"service_reference": "...",
"response_code": "0",
"response_message": "..."
}
}
Transaction flow and processing rules
To ensure transaction integrity and prevent race conditions, SamPay processes bill payments using a multi-step holding and ledger system. A bill payment is successful only when SamPay receives a final approval from the bill payment service.
- Initiation & Validation: When a request is received, the system calculates the applicable fee using our Fee Service. It then verifies that your wallet balance is sufficient to cover the Total Debit (Amount + Fee) and that the Total Debit does not exceed your daily send limit. We also verify that the `reference` is unique.
- Holding State: The transaction is placed in a pending holding state. Your balance is pre-emptively deducted by the Total Debit to prevent race conditions while the external provider is called.
- External Processing: The request is sent securely via our VAS Gateway (cGrate) to process the Airtime, ZESCO, or DStv payment.
- Finalization (Success): If the gateway returns success, the holding state is marked as successful. The balance deduction becomes permanent, limits are updated, and the collected fee is settled. A completed transaction is recorded in your ledger, and you receive a success response along with a `purchase_id` and `voucher_pin_number` (if applicable).
- Finalization (Failure): If the gateway rejects the payment, the transaction is marked as failed. The pre-emptive balance deduction is immediately rolled back to your wallet. You will receive an error response detailing the failure reason.
Payouts & Resolve Recipient
This feature allows merchants to retrieve the details of the recipient using their API credentials. Our payment gateway securely handles the lookup with the underlying institution.
Request body
{
"accountNumber": "260123456789",
"provider": "Zanaco"
}
Success response
{
"status": 200,
"statusCode": "00",
"data": {
"accountNumber": "260123456789",
"accountName": "John Doe",
"msisdn": "260123456789"
}
}
Initiate Payout
This endpoint initiates an outgoing payment request securely via the payment gateway.
Request body
{
"accountNumber": "260123456789",
"amount": 30,
"provider": "Zanaco",
"transactionId": "5171380986887883",
"msisdn": "260123456789",
"extraData": {
"sendersName": "JOHN BWALYA",
"sendersReference": "TESTING"
}
}
Success response
{
"statusCode": 140,
"statusDescription": "Accepted",
"data": null
}
Webhooks
SamPay sends a signed webhook to your callback URL when a payment completes or fails.
Setting up your webhook
Configure your endpoint URL in the Webhook settings.
Webhook payload structure
{
"event": "transaction.success",
"data": {
"reference": "ORD-12345",
"status": "SUCCESSFUL",
"amount": 100.00,
"currency": "ZMW"
}
}
Headers
Content-Type: application/json
X-Webhook-Signature: hmac_sha256_signature
X-Webhook-Event: payment.completed
Verify signature
$payload = file_get_contents('php://input');
$expected = hash_hmac('sha256', $payload, $secretKey);
$valid = hash_equals($expected, $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '');
Appendix: Provider References
Use these exact Provider Name strings in your API requests as the provider parameter when processing payouts.
| Provider Name (provider) | Institution Type | Switch Channel |
|---|---|---|
| AB Bank MNO | Bank | E-money |
| ABBank (Etumba) | Bank | ATM, POS & E-money |
| ABSA | Bank | ATM & POS |
| ABSA MNO | Bank | E-money |
| Access Bank | Bank | ATM & POS |
| Access MNO | Bank | E-money |
| Airtel | MNO | E-money |
| AtlasMara (BancABC) - Access Bank | Bank | ATM & POS |
| Bank of China | Bank | ATM & POS |
| Bayport | PSP | ATM & POS |
| Bayport MNO | PSP | E-money |
| Bevura (Probase) | PSP | E-money |
| cGrate | PSP | E-money |
| cGrate POS | PSP | POS |
| Citibank | Bank | E-money |
| ECO MNO | Bank | E-money |
| ECOBANK | Bank | ATM & POS |
| FAB | Bank | ATM & POS |
| FAB MNO | Bank | E-money |
| FCB | Bank | ATM & POS |
| FCB MNO | Bank | E-money |
| FNB | Bank | ATM & POS |
| FNB MNO | Bank | E-money |
| FTSZ | PSP | ATM & POS |
| Investrust | Bank | ATM & POS |
| Investrust MNO | Bank | E-money |
| IZB | Bank | ATM, POS & E-money |
| Izwe | PSP | POS |
| Jabu Wallet | PSP | E-money |
| Kazang | PSP | E-money |
| Kazang Pay | PSP | POS |
| Lolc Finance | PSP | ATM & POS |
| Mfinance | PSP | ATM, POS & E-money |
| MTN | MNO | E-money |
| Mypay | PSP | E-money |
| Natsave | Bank | ATM & POS |
| Natsave MNO | Bank | E-money |
| Paygo | PSP | E-money |
| Pulse Financial Services (EFC) | PSP | E-money |
| Samafrica / Sampay | PSP | E-money |
| SmartPay | PSP | E-money |
| Stanbic | Bank | ATM, POS & E-money |
| Stdchart | Bank | ATM & POS |
| StdChart MNO | Bank | E-money |
| Tenga (AtlasMara) - Access Bank | Bank | E-money |
| TEST | MNO | BANK |
| UBA | Bank | ATM & POS |
| UBA MNO | Bank | E-money |
| UBA YES Wallet | Bank | E-money |
| Zamtel | MNO | E-money |
| Zanaco | Bank | ATM, POS & E-money |
| ZICB | Bank | ATM & POS |
| ZICB MNO | Bank | E-money |
| ZNBS | Bank | ATM & POS |
| ZNBS MNO | Bank | E-money |
| Zoona | PSP | E-money |