ZonmPay API v2

Collection API

Charge a customer on any channel through one endpoint.

COLLECTION · POSTYou send one request; the customer gets a prompt on their phone and enters their PIN.
HomeDocumentationReceive Payment

Authentication

Every request is authenticated with your secret key in the apiToken header. There is one base URL and one key: your account behaves as a sandbox until go-live is approved, on the same URL. Keep the key server-side only, and note that rotating it expires the previous one immediately.

Required Headers

apiToken

sp_sk_prod_XXXXXXXXXXXX

Content-Type

application/json

Overview

Mobile money, bank accounts, TANQR and till / Lipa Numbers all go through POST /api/v2/payment/collection. You describe who is paying with service + account, and the channel is routed for you: provider is optional for mobile because the network is detected from the number. The call returns immediately with PROCESSING and the final outcome arrives on your webhook.

  • Step 1 — CollectionPOST /api/v2/payment/collection with service + account + amount. You describe who is paying, not how the plumbing works — the channel is routed for you. It returns immediately with status PROCESSING.
  • Step 2 — WebhookWhen the payment reaches a final state we POST payment.confirmed / payment.failed to your URL. Verify the X-SpeedPesa-Signature header before you trust it.
  • Step 3 — ReconcileIf your webhook was unreachable, poll GET /api/v1/payment/reference/{reference} — no more than once every 10 seconds and stop after 5 minutes.
Step 1POST

Collection (Unified)

Charges a customer on any channel through one endpoint. Mobile money, bank accounts, TANQR and till / Lipa Numbers all go through here. Returns immediately with status PROCESSING — the customer has not paid yet, and the final outcome arrives on your webhook.

POST https://zonmpay.com/api/v2/payment/collection

Use zonmpay.com specifically (without www the request is redirected and some HTTP clients drop the POST body — which causes a server error).

Request Body (JSON)

ParameterTypeRequiredDescription
amountintegerYesAmount to collect in TZS. Minimum TZS 100.example: 50000
servicestringYesHow the payer is identified: mobile, account, tanqr or merchant.example: mobile
accountstringYesThe identifier itself: phone number, bank account number, or till id. 0712345678 and 255712345678 are both accepted.example: 255712345678
providerstringNoThe channel, e.g. VODACOM, TIGOPESA, AIRTELMONEY, HALOPESA, TTCL, CRDB. Optional for service: mobile because the network is detected from the number; required for everything else.example: VODACOM
referencestringNoYour own order id. Repeating the same reference returns the existing payment instead of charging again.example: ORDER-001
descriptionstringNoShown to the customer and on your statement.example: Payment for Order #001
amountTypestringNoFULL requires the exact amount, FIXED accepts a single payment of a set amount, FLEXIBLE accepts part payments until the total is met.example: FULL
pushbooleanNoSet false to create the payment without prompting the customer immediately (collect later via a payment link).example: true
bash
curl -X POST https://zonmpay.com/api/v2/payment/collection \
  -H "apiToken: SPP_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "ORDER-001",
    "description": "Payment for Order #001",
    "amount": 50000,
    "service": "mobile",
    "account": "255712345678",
    "amountType": "FULL"
  }'

Note: Store data.reference. It is how you match the webhook and how support traces the payment. Repeating the same reference is idempotent: it returns the existing payment instead of charging twice.

Step 2GET

Get Payment by Reference

Poll-based status check, for when your webhook is unreachable. Use it no more than once every 10 seconds and stop after 5 minutes: a collection that has not resolved within the 90-second USSD window is not going to resolve because you asked again.

GET https://zonmpay.com/api/v1/payment/reference/{reference}

Use zonmpay.com specifically (without www the request is redirected and some HTTP clients drop the POST body — which causes a server error).

Query Parameters

ParameterTypeRequiredDescription
referencestringYesThe ZonmPay reference returned when you created the payment.example: SP008985
bash
curl https://zonmpay.com/api/v1/payment/reference/SP008985 \
  -H "apiToken: SPP_live_YOUR_API_KEY"

Note: feeAmount, feePercent and netAmount are omitted entirely on older payments. Read them with a null check, not a falsy check — an absent feeAmount is not the same as a fee of zero.

POST

Cross-channel Payment (Pay Now)

Re-routes an existing reference to a different channel — for example a customer who created the payment on M-Pesa but wants to pay from an Airtel Money wallet instead.

POST https://zonmpay.com/api/v2/payment/pay

Use zonmpay.com specifically (without www the request is redirected and some HTTP clients drop the POST body — which causes a server error).

Request Body (JSON)

ParameterTypeRequiredDescription
referencestringYesThe existing payment reference.example: SP008985
servicestringYesmobile, account, tanqr or merchant.example: mobile
accountstringYesThe new payer identifier.example: 255684118011
providerstringNoRequired for anything other than mobile.example: AIRTELMONEY
bash
curl -X POST https://zonmpay.com/api/v2/payment/pay \
  -H "apiToken: SPP_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reference": "SP008985", "service": "mobile", "account": "255684118011" }'

Transaction Statuses

PENDING

Created, but the customer has not acted yet: the push is waiting for a PIN, or a link has not been opened.

Action: Wait. Collection only.

PROCESSING

Dispatch is in flight inside ZonmPay.

Action: Wait — no webhook fires on this state.

PROCESSED

Handed to the operator, who accepted it and will call back with the final outcome.

Action: Wait for the final webhook.

AWAITING_APPROVAL

Payout created and waiting for approval. No money has moved.

Action: Approve it with POST /api/v2/payment/approve.

APPROVED

Approved and debited from your wallet; being dispatched.

Action: Wait for payout.confirmed or payout.failed.

SUCCESSFUL

Completed. Money has moved.

Action: Terminal — fulfil the order.

PAID

The requested amount has been received in full.

Action: Terminal — collection only.

PARTIAL

Some of the amount has been paid. Compare paidAmount with amount.

Action: FLEXIBLE collections only. Keep waiting for the balance.

FAILED

Could not complete. failureReason says why. A failed payout is refunded automatically.

Action: Terminal — retry with a new reference.

CUSTOMER_REJECTED

The customer declined the prompt.

Action: Terminal.

REJECTED

Rejected by ZonmPay or the operator before reaching the customer.

Action: Terminal — read the message.

CANCELLED

Cancelled before completion.

Action: Terminal.