Sampay Developer docs

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.

Create payment Signed direct collection request
POST
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

https://payments.sampay.dev/api/v1

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);
POST

Direct initiate payment

Creates a transaction and sends a mobile money prompt to the customer phone number.

POST https://payments.sampay.dev/api/v1/payments/initiate

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."
}
POST

Hosted checkout initiate

Use hosted checkout when SamPay should collect the customer's wallet number or card details on a payment page.

POST https://payments.sampay.dev/api/v1/payments/initiate/checkout

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=..."
}
GET

Check payment status

GET https://payments.sampay.dev/api/v1/payments/{reference}

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"
}
POST

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.

POST https://payments.sampay.dev/api/v1/bills/pay
GET https://payments.sampay.dev/api/v1/bills/{reference}

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
referenceRequired unique merchant reference. Duplicate references are rejected.
serviceRequired. One of airtime, zesco, or dstv.
networkRequired for airtime only. One of mtn, airtel, or zamtel.
amountRequired decimal amount in Kwacha.
account_numberRequired. Airtime phone number, ZESCO meter number, or DStv account/smartcard number.
callback_urlOptional 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.

  1. 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.
  2. 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.
  3. External Processing: The request is sent securely via our VAS Gateway (cGrate) to process the Airtime, ZESCO, or DStv payment.
  4. 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).
  5. 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.
POST

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.

POST https://payments.sampay.dev/api/v1/payouts/resolve-recipient

Request body

{
  "accountNumber": "260123456789",
  "provider": "Zanaco"
}

Success response

{
  "status": 200,
  "statusCode": "00",
  "data": {
    "accountNumber": "260123456789",
    "accountName": "John Doe",
    "msisdn": "260123456789"
  }
}
POST

Initiate Payout

This endpoint initiates an outgoing payment request securely via the payment gateway.

POST https://payments.sampay.dev/api/v1/payouts/initiate

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