Payments
Creating a payment
Section titled “Creating a payment”POST /api/v1/gateway/payments (scope payments:write) creates a payment priced in Ghana cedis.
| Field | Required | Notes |
|---|---|---|
amount |
Yes | GHS amount as a decimal string, for example "100.00". At most 8 decimal places. |
crypto_type |
Yes | The coin the customer pays with, for example USDT_TRC20. See supported coins. |
fiat_currency |
No | Only GHS is accepted. |
order_id |
No | Your order reference, up to 128 characters. Returned on the payment and in webhooks. |
description |
No | Shown to the customer, up to 500 characters. |
idempotency_key |
No, but strongly recommended | See Idempotency. |
callback_url |
No | Restricts this payment’s webhooks to one registered endpoint. See Webhooks. |
redirect_url |
No | Stored with the order terms. BitMomo does not redirect the customer to it automatically. |
metadata |
No | Your own key/value data, up to 4 KB and 3 levels deep. Keys starting with _, bitmomo_, cryptopos_ or server_ are reserved. |
The response contains everything needed to collect the payment: the locked crypto amount and rate, the deposit address and network, a qr_code_data payment URI, and expires_at. Send the customer to the hosted checkout at https://customer.dev.bitmomo.app/pay/{id}, or build your own page from those fields.
Always take the price from your own server-side order record, never from the browser.
Idempotency
Section titled “Idempotency”Network calls can time out after BitMomo has already created the payment. To make retries safe:
- Generate an
idempotency_keyfor the order (the SDK’snewIdempotencyKey()returns a UUID). - Save it with the order before calling BitMomo.
- Send the same key on every retry for that order.
Repeating a request with the same key returns the original payment instead of creating a second one. Reusing a key with different details (for example another amount) is rejected with 409.
Statuses
Section titled “Statuses”A payment moves through these statuses:
| Stage | Statuses |
|---|---|
| Waiting for the customer | created, locked, pending |
| Payment seen on chain | detected, confirming, confirmed, settling |
| Final | completed, expired, failed, cancelled |
| Held for review | flagged, needs_review, orphaned |
completed: the funds are confirmed and credited to your account.expired: the quote window passed without an accepted payment. Create a new payment if the customer still wants to pay.cancelled: the payment was cancelled before completion.needs_review: BitMomo is holding the payment for a manual check. Do not fulfil until it reachescompleted.
Statuses are lowercase with underscores. Treat any status you do not recognise as “not paid yet”.
Reading a payment
Section titled “Reading a payment”GET /api/v1/gateway/payments/{id} (scope payments:read) returns the full private view of one of your payments. Fields to check before fulfilling an order:
| Field | Meaning |
|---|---|
status |
Must be completed. |
environment |
test today; must match the environment of your order. |
order_terms.order_id |
Must be the order you are fulfilling. |
economics.invoice_ghs |
The amount you asked for. |
economics.recognized_gross_ghs |
The amount BitMomo recognised from what the customer actually paid. |
economics.merchant_net_ghs |
What you receive after fees. |
economics.surplus_ghs |
Any overpayment held separately. |
payout |
Payout state for this payment. It is separate from whether the customer paid. |
economics is null until the payment completes. completed alone does not prove the customer paid the full price: compare recognized_gross_ghs with your order amount. If you accept underpayment (for example a discount), make that an explicit rule in your own system.
All money values are decimal strings. Compare them exactly; never convert them to floating-point numbers.
Listing payments
Section titled “Listing payments”GET /api/v1/gateway/payments (scope payments:read) returns your payments, newest first. Use page and limit (up to 100) to paginate and status_filter to filter by status. Each row includes environment and recognized_amount_fiat.
Balances
Section titled “Balances”GET /api/v1/gateway/balances (scope payments:read) returns exact balances as decimal strings, for example ghs_available_exact, together with per-currency and per-asset balances. Older numeric fields in the same response are for display only.
Polling versus webhooks
Section titled “Polling versus webhooks”Use webhooks to learn about changes, and GET /gateway/payments/{id} to confirm them. If your webhook endpoint was down, list recent payments to catch up; do not rely on webhooks alone.