Skip to main content
The Payments API lets you list the payments collected for your project and mint one-time deposit accounts that settle into a wallet top-up or a subscription. Depending on the settlement rail, a deposit account is either a fiat bank account (bank transfer in NGN) or a stablecoin deposit wallet (USDC or cNGN, on-chain).

How funding works

  1. Mint a deposit account with Create deposit account, stating the purpose: a subscription (planId + billingCycle) or a wallet top-up (USD amount).
  2. The payer sends the exact amountExpected to the account before expiryAt: a bank transfer for FIAT, an on-chain token transfer for STABLECOIN.
  3. Settlement is automatic: the deposit is verified, an idempotent payment record is written, and the purpose is applied: the subscription activates (with product access granted) or the wallet balance is credited.
The step-by-step version, including per-rail payer instructions, lives in the Fund and subscribe guide.

The payment object

The deposit account object

Returned by Create deposit account in the data array, one entry per active provider. Each account is bound to a single expected amount and expires. The object is a discriminated union on kind: the keys present depend on the rail, and you only ever receive the keys for that rail. Always branch on kind; do not assume a field exists across both.
A FIAT account carries no on-chain keys (walletAddress, token, chainId, …) and a STABLECOIN account carries no bank keys (accountNumber, bankName, …). The irrelevant keys are absent, not null.

FIAT: bank transfer

STABLECOIN: on-chain deposit

For a cNGN deposit, show the payer the naira value, e.g. Send ₦22,556.39 (22,556.39 cNGN). For USD-pegged tokens, show the token amount, e.g. Send 15 USDC.

FX rate lock

Every amount in a deposit-account response is priced at a single NGN/USD rate, returned as fxRate (USD per 1 NGN). The rate is locked for the life of the account: when the deposit lands, settlement converts at the quoted rate, not the live market rate, so what the payer owes and what gets credited can’t drift inside the deposit window. After expiryAt the lock (and the account) expires; request a new account to get a fresh rate.

Subscription upgrades are prorated

If the project already holds an active paid subscription to a different plan of the same product, a subscription request is treated as an upgrade:
  • The unused value of the current subscription (current plan price × fraction of the billing period remaining) is credited against the new plan’s price.
  • Only the difference is charged. All amounts in the response already reflect the credit, priced at the locked fxRate.
  • When the payment settles, the new subscription starts a full fresh period, the old subscription is cancelled, and its product access is replaced by the new plan’s.
  • Moving from a free plan to a paid plan of the same product works the same way, just with no credit: full price is charged, and the free subscription and its access grant are replaced on settlement.
  • If the credit would cover the entire new price (a downgrade or near-equal switch), the request is rejected: no-charge plan switches are not supported.
No special request field is needed: upgrades are detected server-side, and a renewal is just a new request with the same planId.