If you’d rather not choose, or want all three on one page, use payment links and let the payer pick.
Mobile money charge
You know the payer’s number and the amount. You ask; they approve on their phone.pending while the prompt sits on their phone; it becomes completed (balance credited, collection.completed fires) or failed (declined, timed out, wallet error: collection.failed). A timeout is normal: people put their phone down. Let them retry.
Virtual account
A real bank account number that belongs to your organization. Give it to a customer; whatever they transfer credits your balance.externalReference is yours, so you can tell later whose money arrived. Each inbound transfer fires account.credited and shows up as a collection. Pause an account with PATCH … { "status": "paused" }.
This is the rail that makes Nigeria work, and the one to reach for whenever the payer, not you, decides the amount.
Ghana (GHS): set a representative first
GHS virtual accounts are real accounts at UMB, and the bank opens them against a named Ghanaian identity: your organization representative. Set it once, as an owner or admin, before your first GHS account: in the dashboard (Add funds → Bank transfer in GHS asks for it) or with a team-member session:POST /v1/virtual-accounts { "currency": "GHS" } works with any key that has collections:write. Before it, the call returns 422 naming the missing representative, so check GET /v1/organization/representative (null until set) if your integration provisions GHS accounts on demand.
In sandbox you can skip this. Without a representative, sandbox uses your organization owner’s name (the name you signed up with), with placeholder phone and ID. GET /v1/organization/representative returns it with status: "sandbox_default", and GHS accounts open straight away with that name as accountName. Setting a representative replaces the default. Production never fills one in, so set a real one before you go live.
- API keys can read the representative but not set it (
403). It is a person’s identity, so it stays with the humans on your team. - Every GHS account’s
accountNameis the representative’s name as the bank holds it, which is the name your customer sees in their bank app before confirming the transfer. - The bank registers the representative when your first GHS account is opened. Editing
fullNameoridNumberafterwards doesn’t reach the bank; email api-support@chippercash.com if your representative actually changes. - GHS accounts are one-per-customer only. Hosted checkout doesn’t offer bank transfer in GHS; Ghanaian payers use mobile money there.
Crypto address
A deposit address for one asset on one chain.GET /v1/capabilities → deposits (testnets on sandbox).
Tell your customer the asset and the chain. USDC sent on the wrong network to a Solana address is gone.
Funding your own balance
The same two mechanisms are how you top up in production: create a virtual account or a crypto address in your own name and transfer to it, or use Add funds in the dashboard, which does exactly that.What “received” means
All three end the same way: a ledger credit on your balance (available rises), an account.credited webhook, and a row in GET /v1/transactions. Reconcile on externalReference where you set one, or on the virtual account / address id where the payer chose the amount.