Skip to main content
A wallet holds tokens. A rail is a channel that moves value between those tokens and the outside world — a bank transfer, a cash agent, an on-chain address. Picking the rail is usually the first decision: it determines the currency, the direction, and the identifier you have to collect from the user.

Every rail

Swapping between two tokens you already hold is not a rail — no money enters or leaves. That is POST /v1/users/{userId}/exchange/convert.
A rail becoming available is gated on the matching onboarding, not just on KYC being complete. Each currency needs its own activation — see the integration flow and the per-region KYC pages.

The signature pattern

Most outbound rails do not move money on the call that creates them. They return something to sign, and the transfer only proceeds once the signature comes back:
  1. Create the payout / order. The response carries a signatureRequest (or a workflowId plus a hash), usually alongside a quote.
  2. Sign it on-device with the wallet owner key via bmoni_embedded_sdk — the key registered as userOwnerAddress at wallet creation.
  3. Submit it:
The Nigerian offramp is the exception in shape: it creates a proposal that needs approval before signing. See NGN rails.

Bank payouts

A single rail that pays out to bank accounts across many countries, funded from USDB. Use it when the destination country has no dedicated rail of its own.

1. Find the country and bank

banks takes an ISO alpha-3 country code and returns bank IDs to use downstream. Branches only exist for some banks — treat an empty list as “no branch needed”, not an error.

2. Validate the destination

routingNumber is also accepted, for rails that require one. Validate before creating the payout so the user can fix a wrong account number while it is still cheap.

3. Create the payout

amount here is in minor units"100000000", not "100.00". This is inconsistent with the Nigerian offramp, where fromAmount is a decimal string like "100.00". Sending "100.00" to a minor-units field, or a minor-units integer to a decimal one, will not be rejected as a type error; it will move the wrong amount. Check which one you are calling.
The response is a signature request plus a quote. Finish it with the signature pattern above.

Crypto in and out

The wallet’s tokens can also arrive from, or leave to, an external on-chain address. No fiat is involved, so there is no quote and no local identifier.

In — get a deposit address

supported-assets lists the enabled chains and tokens; it is not user-scoped, so you can call it before onboarding to build a picker. deposit/wallet returns the address to show:
Tokens seen at that address are credited to the wallet. Supported currencies include USDC, USDT, USDB, DAI, EURC, PYUSD, and USDP — call supported-assets for the live list rather than hardcoding it.

Out — send to an external address

Check supported/{currency} first — the chain and token pair has to be one the rail actually supports. This returns a signature request; finish it with the signature pattern.