Collect a payment
A complete guide to collecting payments through MTN Mobile Money, Airtel Money, and Multi-channel Card/Bank Checkout via TransactPay.
Overview & Channel Selection
The API includes MTN MoMo, Airtel Money, and TransactPay order routes. The default server configuration targets MTN environment mtnrwanda and Airtel country RW with currency RWF. Live market, card brands, and provider activation still need client confirmation.
/payment/gateway-momo-pay) exists for server-to-server calls — keep x-api-secret on your server only.| Payment Channel | Target Audience | Authorization | Supported Currencies | Settlement & Customer UX |
|---|---|---|---|---|
| MTN MoMo (API Key) | Automated backend servers, POS, cron jobs | x-api-key & x-api-secret | 3-letter code. Example uses RWF. | Prompts customer with USSD on handset; poll status until completed. |
| MTN MoMo (Session) | Single-page web apps, mobile apps with login | Authorization: Bearer <token> | 3-letter code. Example uses RWF. | Authenticated merchant session; prompts customer phone via USSD. |
| Airtel Money | Airtel subscribers in the configured country. Default config is RW. | Authorization: Bearer <token> | 3-letter code. Example uses RWF. | Direct mobile collection; synchronous debit payload returned from Airtel. |
| Card & Bank (TransactPay) | Card and bank order routes. Live brands are unconfirmed. | Authorization: Bearer <token> | Currency sent on the order. Example uses RWF. | Two-step order workflow: Create order, then charge card or bank transfer. |
Channel 1: MTN MoMo via Merchant Bearer token
POST/payment/mtn-momo-pay authenticates with Authorization: Bearer <merchant_jwt_token>. The JSON field is phoneNumber, not phone.
phoneNumber is the paying customer's MTN MSISDN (USSD prompt). The customer does not need a Ziba Pay account. If that MSISDN already belongs to a Ziba user it is linked on the order. The API returns 400 if it is the merchant's own phone number.
Upon submitting the request, MTN dispatches an interactive USSD prompt to the subscriber's handset. Extract the transactionReferenceId and poll the status endpoint until terminal confirmation.
curl -X POST "https://payment-service-mh2d.onrender.com/api/payment/mtn-momo-pay" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <merchant_token>" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"phoneNumber": "+250788000000",
"amount": 1000,
"currency": "RWF"
}'Channel 1b: Gateway API keys (server-to-server)
Gateway section only: POST/payment/gateway-momo-pay authenticates with x-api-key and x-api-secret. Prefer /payment/mtn-momo-pay for published samples unless your integration is pure server-to-server with gateway keys.
curl -X POST "https://payment-service-mh2d.onrender.com/api/payment/gateway-momo-pay" \
-H "Content-Type: application/json" \
-H "x-api-key: your_gateway_api_key" \
-H "x-api-secret: your_gateway_api_secret" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"phoneNumber": "+250788000000",
"amount": 1000,
"currency": "RWF"
}'Channel 2: MTN MoMo via JavaScript session
If your frontend already maintains a merchant login session, call POST/payment/mtn-momo-pay with Authorization: Bearer <merchant_jwt_token>.
const response = await fetch("https://payment-service-mh2d.onrender.com/api/payment/mtn-momo-pay", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${merchantToken}`,
"Idempotency-Key": crypto.randomUUID()
},
body: JSON.stringify({
phoneNumber: "+250788000000",
amount: 1000,
currency: "RWF"
})
});
const data = await response.json();
console.log("Track status with reference:", data.transactionReferenceId);Channel 3: Airtel Money
For Airtel, use POST/payment/airtel-momo-pay with a merchant bearer token. Country and currency are taken from server configuration. The example configuration uses Airtel UAT, country RW, and currency RWF, so live Airtel is not confirmed.
The HTTP 200 response returns the raw JSON payload produced directly by Airtel's upstream OpenAPI gateway without a Ziba Pay wrapper envelope.
curl -X POST "https://payment-service-mh2d.onrender.com/api/payment/airtel-momo-pay" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <merchant_token>" \
-d '{
"amount": 1500,
"number": "788000000",
"reference": "order-1042"
}'Channel 4: Card & Bank Checkout (TransactPay)
Card and bank payment routes use the TransactPay integration. Before creating orders, ensure your merchant account KYC status is VERIFIED.
TransactPay collections follow a structured 2-step workflow:
- Step 1: Call POST/payment/zibapay/order/create with
order.amount,order.currency,order.description, andredirectUrlto register the order reference. - Step 2 (Card): Call POST/payment/zibapay/card/:reference with
card.cardnumber,card.expirymonth,card.expiryyear,card.cvv, country, and paymentoption. - Step 2 (Bank Transfer): Call POST/payment/zibapay/bank/:reference with
BankTransfer.bankcode, country, and paymentoption. - Step 3: Poll POST/payment/zibapay/order/status/:reference or POST/payment/zibapay/order/verify/:reference to verify final payment outcome.
Idempotency & Duplicate Prevention
Network drops and client timeouts can occur during mobile money collections. To prevent charging a customer twice when retrying a request, always provide a unique Idempotency-Key header (UUID v4) or an idempotencyKey parameter in the JSON request body.
If Ziba Pay receives a collection request with an Idempotency-Key that has already been processed within the last 24 hours, it returns the cached HTTP 200 response without initiating a second debit on the telecom network.