Direct API
Base URL and environments
Every request goes to one base URL — there is no separate sandbox URL:
https://api.lango.co.zw/v1Which environment you hit is decided by your API key, not the address:
| Key prefix | Environment | Providers | Money |
|---|---|---|---|
sk_test_… | Sandbox | Simulated | No real money, ever |
sk_live_… | Live | Real providers | Real money |
Same endpoints, same base URL for both — you only swap the key. Both keys live in your dashboard under Developers → Applications. (Test and live are isolated at the key level, so a test key can never move real money — see Sandbox and test numbers.)
Charge a known number directly
If you collect the customer’s EcoCash number in your own product (a delivery app, a utility’s
own portal), charge directly: one call with customer.msisdn, and the PIN prompt goes to the
phone immediately.
curl https://api.lango.co.zw/v1/payments \ -H "Authorization: Bearer sk_test_YOUR_KEY" \ -H "Idempotency-Key: order-4417" \ -H "Content-Type: application/json" \ -d '{ "amount": 10000, "currency": "USD", "method": "ecocash", "reference": "ORD-4417", "customer": { "msisdn": "263771234567" }, "metadata": { "order_id": "4417", "depot": "harare-north" } }'The response is awaiting_customer: the prompt is on their phone. From here:
- Listen for the webhook (
payment.succeeded/payment.failed/payment.expired) — the right way; or - Poll
GET /v1/payments/{id}— acceptable for low volume; back off to every few seconds.
Your responsibilities in this mode
Because your UI owns the experience, the checkout page’s protections become your job:
- Show the fee before charging if your customer bears it.
charged_amountin the create response (or preview beforehand) is the number they must see. Surprising people on the PIN prompt kills conversion and trust. - Handle
unknownhonestly. “We’re confirming with EcoCash — don’t pay again.” Never “failed” while it’s stillunknown. The whole page on this is required reading for direct integrations. - Tell them to check their phone — with the masked number (
customer_msisdn_maskedin the response) and a countdown matching the payment’sexpires_at. - Validate numbers loosely, submit strictly. Accept
0771 234 567from humans; send263771234567. Lango normalises common Zimbabwean formats and rejects what can’t be a Zimbabwean mobile number, with a human-readable message you can show verbatim.
Metadata
metadata stores up to your own JSON object on the payment and comes back on every read and
webhook — use it for your internal ids so reconciliation is a lookup, not a join.
Listing and pagination
GET /v1/payments?limit=25&starting_after=pay_... pages newest-first. Filters: status,
method, currency, and search (matches references). The dashboard’s payment list is this
endpoint.