Conversions · for businesses
See the rate.
Then convert.
Quote first. The rate, our margin, the amount you get and how long the quote is held come back before anything moves. Accept it, and that is the rate we settle — between NGN, GHS and KES. ZAR and USD are coming soon.
1POST /v1/quotes23{4 "sourceCurrency": "NGN",5 "destinationCurrency": "KES",6 "amount": 5000000,7 "transactionType": "conversion"8}
1201 Created23{4 "id": "qte_8xk2…",5 "sourceCurrency": "NGN",6 "sourceAmount": "5000000",7 "destinationCurrency": "KES",8 "rate": "0.0836",9 "marginAmount": "2090",10 "destinationAmount": "415910",11 "expiresAt": "…T09:05:00Z"12}
Amounts in minor units. Rate and margin are illustrative.
What a conversion goes through
Four words your customer sees. The same four your dashboard and your webhooks use.
- pending
On request
You send the quote id with POST /v1/conversions. The quote is claimed — it cannot be used again — and the source amount is held on your wallet.
- processing
It’s moving
The exchange runs at the held rate. Where a partner performs it, we wait for the partner’s confirmation rather than assume one.
- successful
It landed
Both wallets update in one balanced entry: source out, destination in, margin booked. Your webhook fires.
→ conversion.successful
- failed
Rarely
It did not complete. The held amount is back in your source wallet in full — no margin, no fee — and your webhook says why.
→ conversion.failed
Why the rate holds
Three mechanics make the promise true. All three are in the engine.
The quote you accept is the rate we settle.
The rate is mid-market. Our margin is its own number in the quote, in the currency you receive — not a footnote. Accept within the hold and the settlement uses those exact figures. Held for five minutes by default; your account can carry its own window.
Each corridor has a road, and the status reads the same on all of them.
Some pairs we book on our own liquidity. On others a licensed partner performs the exchange, and we hold your funds until that partner confirms a final status. Either way the status is pending, processing, successful or failed.
Two currencies, two balanced legs, one entry.
The source leg debits your wallet and credits the counterparty in the source currency. The destination leg does the reverse in the destination currency, with the margin posted to its own revenue account. No account ever mixes currencies.
As your finance team sees it
Every conversion, its rate, its margin — filter, export, drill to the ledger.
Illustrative rows and rates.
The entry behind it
What the ledger records when ₦50,000 becomes Kenyan shillings.
| Account | Debit | Credit |
|---|---|---|
| merchant_wallet | ₦50,000.00 | |
| external_counterparty | ₦50,000.00 |
Debits equal credits — or the ledger refuses the entry.
| Account | Debit | Credit |
|---|---|---|
| external_counterparty | KSh 4,180.00 | |
| merchant_wallet | KSh 4,159.10 | |
| revenue_fx_margin | KSh 20.90 |
Debits equal credits — or the ledger refuses the entry.
Both legs post in one atomic entry. Account names are the real ledger families.
Also on the road
The rest of what ships with conversions today.
- Auto-convertA payout whose sourceCurrency differs from its destinationCurrency converts first, then pays out — one request, one reference, one status.Live
- Quote onceA quote converts exactly once. A second POST /v1/conversions with the same quoteId is refused — two requests can never spend one quote.Always on
- Configurable holdQuotes hold for five minutes by default. Your account can carry a longer or shorter window; the expiresAt in every quote tells you which.Live
- IdempotencySend the same Idempotency-Key twice and you get the same conversion back — never a second debit.Always on
Live currencies: NGN, GHS, KES · ZAR and USD coming soon · as of 25 Sep 2026. Full coverage →
Your first quote is a sandbox call away.
No setup fee. Sandbox keys on signup. Rate and margin in every quote.