Skip to content

Topup intents ​

Start a top-up the customer approves on their phone ​

POST/api/v1/tenant/topup-intents

Scope topup-intents:write · Write — send Idempotency-Key and X-Request-Id

Creates a topup_c2b operation in state pending_provider with a 12-digit intentReference and an expiresAt, and sends a payment prompt for the exact amount to the customer's verified phone number — the one you name in payerIdentifierUid, else the primary one, else the one added first; no money moves yet. railCode names the payment provider; one that cannot take the payment is refused with 422 RailUnavailable, and a customer with no verified phone number, or a payerIdentifierUid that is not one, with 422. The wallet is credited when the customer approves the prompt before the intent expires (topup.confirmed). A prompt that is declined or not answered is not sent again: the intent fails at expiresAt (topup.expired).

Request body ​

FieldTypeRequiredDescription
walletUidstringyesThe wallet the top-up credits, as returned by POST /tenant/customers.
amountstringyesA positive amount with at most two decimal places; the exact amount the payer must pay in.
currencystringyesISO-4217; must equal the wallet's currency.
railCodestringyesCode of the payment provider the payer will pay through; it must accept incoming payments. At most 64 characters.
payerIdentifierUidstring | nullnoThe customer's phone number to send the payment prompt to, for this top-up only: an identifiers[].uid from GET /tenant/customers/{uid} that is a verified phone number of the wallet's customer, otherwise 422. Omit it to prompt the default: the primary verified phone number, else the verified phone number added first. Only for a payment provider that prompts the customer's phone; anywhere else 422. At most 26 characters.
expiresInSecondsobjectnoLifetime of the intent in seconds; defaults to the payment provider's usual lifetime, else one hour. Min 60. Max 86400.
clientReferencestringyesYour own reference; stored and returned verbatim, never interpreted; unique within your account.
Example (placeholder values)
json
{
  "walletUid": "01J9Z3K5X8QW2R4T6V8Y0B1C3D",
  "amount": "2500.00",
  "currency": "ETB",
  "railCode": "string",
  "clientReference": "string"
}

Response · 201 ​

FieldTypeDescription
uidstring
typestringOperation type, e.g. wallet_credit, wallet_debit, payout_b2c or topup_c2b.
statestringOperation state: created, awaiting_authorization, authorized, held, processing, pending_provider, confirmed, failed, reversed or completed.
amountstringA decimal amount with two decimal places.
feestringA decimal amount with two decimal places.
taxstringA decimal amount with two decimal places.
currencystringISO-4217.
clientReferencestring | nullYour reference, exactly as you supplied it.
sourceWalletUidstring | nullWallet transfers only: the wallet the money left.
destinationWalletUidstring | nullWallet transfers only: the wallet the money reached.
createdAtstring
completedAtstring | nullWhen the operation first reached a final state.
linksobject
links.selfstringAPI-relative path of this operation (GET /tenant/operations/{uid}).
links.receiptstringAPI-relative path of its receipt (GET /tenant/operations/{uid}/receipt).
intentReferencestringThe top-up's reference with the payment provider; 12 digits.
expiresAtstringAfter this instant a payment for this top-up is no longer credited.
railCodestringThe payment provider's code the intent was issued on.
payerInstructionsstring | nullInstructions to show the payer for this payment provider; null when there are none.
Example (placeholder values)
json
{
  "uid": "01J9Z3K5X8QW2R4T6V8Y0B1C3D",
  "type": "string",
  "state": "string",
  "amount": "2500.00",
  "fee": "12.50",
  "tax": "1.88",
  "currency": "ETB",
  "clientReference": "string",
  "sourceWalletUid": "01J9Z3K5X8QW2R4T6V8Y0B1C3D",
  "destinationWalletUid": "01J9Z3K5X8QW2R4T6V8Y0B1C3D",
  "createdAt": "2026-09-03T10:15:30.000Z",
  "completedAt": "2026-09-03T10:15:30.000Z",
  "links": {
    "self": "string",
    "receipt": "string"
  },
  "intentReference": "048213775902",
  "expiresAt": "2026-09-03T10:15:30.000Z",
  "railCode": "string",
  "payerInstructions": "string"
}

Errors ​

400 401 403 404 409 422 429 500 503 — one body shape for all of them, see Errors.