Skip to main content

Collect payments with ZenoPay

ZENOPAY pushes a payment request to the payer’s mobile-money wallet. The payer authorizes it on their handset, and the order is polled to completion. Available to ISPs in Tanzania (TZ), alongside ClickPesa, AzamPay, PalmPesa, PawaPay, PesaPal, Relworx, PayPal, and DPO.

Before you start

  1. Complete ZenoPay merchant onboarding in an account owned by the ISP.
  2. Collect the API key from the ZenoPay merchant dashboard.
  3. Confirm your workspace is reachable from the public internet, so ZenoPay can deliver its webhook.

Configure the gateway

1

Open Settings → Payments → ZenoPay

Select ZenoPay from the payment marketplace.
2

Enter the API key

API key (required) is stored as a secret and is not echoed back into the form after saving. It is sent as the x-api-key header on every request.
3

Leave the API host blank unless ZenoPay told you otherwise

API host (optional) overrides the endpoint Centipid Billing calls. Leave it empty to use the default ZenoPay host.
4

Run a controlled test payment

Pay a small amount from the captive portal. Verify the wallet prompt arrives, the payment lands in the ledger with method ZenoPay, and the subscriber’s package is applied.

Credentials

Callback URLs

The webhook address is sent with every payment request, so there is nothing to register in the ZenoPay dashboard. Settings → Payments still shows it under Callback URLs (https://<your-host>/api/zenopay/webhook) so you can confirm the address ZenoPay will call, and check it is not blocked by a firewall or WAF rule.

What the payer must provide

  • Email address (required). ZenoPay rejects an order without one, so the captive portal asks the payer for an email when your account is on ZenoPay. The customer portal uses the email on the subscriber’s profile, so add one there before directing a subscriber to the portal. Without a valid email, checkout stops with “A valid email address is required for ZenoPay payments” before any request reaches ZenoPay.
  • Tanzanian phone number (required). Accepted in local or international form; it is normalized before it is sent.
  • Amount. Rounded to a whole number before the request is sent.
Because authorization happens on the payer’s handset rather than in a hosted checkout page, no ZenoPay domain needs to be added to the captive walled garden.

How a payment completes

1

Request

Centipid Billing posts the order to /api/payments/mobile_money_tanzania with an order id it generates itself. That id is the local transaction reference, so the handle everything reconciles against exists before ZenoPay answers.
2

Authorization

The payer approves the request on their phone.
3

Confirmation

A background job polls /api/payments/order-status every 5 seconds, for up to 40 attempts (about 3 minutes 20 seconds), until the order reaches a terminal state. This poller — not the webhook — is what completes the payment, so a payment still completes when the payer closes the captive browser mid-checkout.
4

Provisioning

On COMPLETED, a payment is recorded with method ZenoPay and the subscriber’s package is applied asynchronously. On FAILED, the reason is stored against the transaction and nothing is credited.
ZenoPay’s webhook carries no signature, HMAC, or shared secret in its body, so it cannot prove it came from ZenoPay. Centipid Billing treats it as a hint only: nothing is credited from the webhook body. Every credit is made against a status read from ZenoPay with your own API key, so a spoofed “completed” webhook cannot provision a subscriber.
A failed request is deliberately not retried automatically. An automatic retry after a lost response could raise a second prompt on the same order and charge the payer twice. The payer retries by choice instead.

Troubleshooting

For symptoms that are not specific to ZenoPay, see Payment troubleshooting. For every other gateway’s fields, see the credential reference.