Idempotency
Networks fail after the server acted as often as before. If you POST a charge, the connection drops, and you retry — did you charge once or twice? With idempotency keys, the question disappears.
How it works
Every POST that creates something takes an Idempotency-Key header (it’s required on
POST /v1/payments). The key is any string up to 255 characters that uniquely identifies the
attempt — an order id is usually perfect.
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" }'- Same key + same body → you get the original response back, replayed. No second charge, ever. Safe to retry as hard as you like.
- Same key + different body →
409 idempotency_key_reused. You almost certainly have a bug; we refuse rather than guess which body you meant. - Same key while the first attempt is still running →
409 request_in_progress. Back off and retry; you’ll get the replay.
Keys are held for 24 hours.
References are a second net
Independently of idempotency, every payment carries your reference, and a reference is
unique per merchant. Reusing one returns 409 reference_in_use with the existing payment
to fetch instead. Between the two mechanisms, “charged twice because we retried” is not a
failure mode a Lango integration has.
The rule of thumb
Generate the key where the intent originates (your order id, your invoice number), not at the HTTP call site. Then any layer of your stack can retry safely — job queues, load balancers, a user mashing F5 — and the worst case is always the same response twice, never the same charge twice.