Collection flows
Collecting a payment always has the same shape: authenticate, initiate, sometimes
confirm, then check status. The only thing that changes between providers is the middle
step — and it’s decided by the method’s flow, which you read from
GET /v1/payment-methods rather than hard-coding.
| Provider | flow | The steps |
|---|---|---|
| EcoCash, OneMoney | push | Initiate → Check status |
| InnBucks | code | Initiate (returns a code) → Check status |
| O’mari | otp | Initiate → Confirm OTP → Check status |
Step 0 — Authenticate (every call)
One base URL for test and live — your key decides which. Send it as a bearer token, and put an
Idempotency-Key on every POST so a retry can never charge twice.
# sk_test_… = sandbox (no real money) · sk_live_… = real money-H "Authorization: Bearer sk_test_YOUR_KEY"-H "Idempotency-Key: a-unique-id-per-charge"Amounts are always in minor units (1000 = USD 10.00). Numbers like phone numbers go in as
263771234567.
Push — EcoCash, OneMoney
A prompt is pushed to the customer’s phone and they approve it there. You never touch their PIN.
-
Initiate. The prompt lands on the phone; the payment comes back
awaiting_customer.Terminal window 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": 1000,"currency": "USD","method": "ecocash","reference": "ORD-4417","customer": { "msisdn": "263771234567" }}' -
Check status. Prefer the
payment.*webhook; polling is fine at low volume (back off to a few seconds).Terminal window curl https://api.lango.co.zw/v1/payments/pay_123 \-H "Authorization: Bearer sk_test_YOUR_KEY"
Code — InnBucks
A code is issued and the customer approves it in the InnBucks app or by *569#. USD only.
-
Initiate. The response is
awaiting_code_useand carries anext_actionblock: thecodeto show, anexpires_at, theinstructions, the InnBuckslogo_url, andpoll_interval_seconds(30). Show the code and instructions to the customer, under the InnBucks logo.Terminal window curl https://api.lango.co.zw/v1/payments \-H "Authorization: Bearer sk_test_YOUR_KEY" \-H "Idempotency-Key: order-4418" \-H "Content-Type: application/json" \-d '{"amount": 1000,"currency": "USD","method": "innbucks","reference": "ORD-4418","customer": { "msisdn": "263771234567" }}' -
Check status — at most once every 30 seconds. Poll
GET /v1/payments/{id}until it readssucceeded. Polling faster than once per 30s is refused with a429(Retry-After) — an InnBucks rule, enforced by the API.
OTP — O’mari
The customer is sent a one-time PIN and enters it to confirm — a two-step rail.
-
Initiate. The OTP is sent to the phone; the payment comes back
awaiting_otpand acheckout_token— you need that token for the next step.Terminal window curl https://api.lango.co.zw/v1/payments \-H "Authorization: Bearer sk_test_YOUR_KEY" \-H "Idempotency-Key: order-4419" \-H "Content-Type: application/json" \-d '{"amount": 1000,"currency": "USD","method": "omari","reference": "ORD-4419","customer": { "msisdn": "263771234567" }}' -
Confirm the OTP. The
checkout_tokenis the credential here (no API key). A successful confirm is the real debit.Terminal window curl https://api.lango.co.zw/v1/checkout/CHECKOUT_TOKEN/otp \-H "Content-Type: application/json" \-d '{ "otp": "123456" }' -
Check status.
GET /v1/payments/{id}should now readsucceeded.
Where next
- Let the customer pick the method and enter the OTP/PIN on a page you don’t build → Hosted checkout and Embeddable checkout.
- Own the whole flow in your own UI → Direct API.
- Every field and response → the API reference or the OpenAPI spec.