Appearance
Topup intents
Start a top-up the customer approves on their phone
POST
/api/v1/tenant/topup-intentsScope 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
| Field | Type | Required | Description |
|---|---|---|---|
walletUid | string | yes | The wallet the top-up credits, as returned by POST /tenant/customers. |
amount | string | yes | A positive amount with at most two decimal places; the exact amount the payer must pay in. |
currency | string | yes | ISO-4217; must equal the wallet's currency. |
railCode | string | yes | Code of the payment provider the payer will pay through; it must accept incoming payments. At most 64 characters. |
payerIdentifierUid | string | null | no | The 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. |
expiresInSeconds | object | no | Lifetime of the intent in seconds; defaults to the payment provider's usual lifetime, else one hour. Min 60. Max 86400. |
clientReference | string | yes | Your 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
| Field | Type | Description |
|---|---|---|
uid | string | |
type | string | Operation type, e.g. wallet_credit, wallet_debit, payout_b2c or topup_c2b. |
state | string | Operation state: created, awaiting_authorization, authorized, held, processing, pending_provider, confirmed, failed, reversed or completed. |
amount | string | A decimal amount with two decimal places. |
fee | string | A decimal amount with two decimal places. |
tax | string | A decimal amount with two decimal places. |
currency | string | ISO-4217. |
clientReference | string | null | Your reference, exactly as you supplied it. |
sourceWalletUid | string | null | Wallet transfers only: the wallet the money left. |
destinationWalletUid | string | null | Wallet transfers only: the wallet the money reached. |
createdAt | string | |
completedAt | string | null | When the operation first reached a final state. |
links | object | |
links.self | string | API-relative path of this operation (GET /tenant/operations/{uid}). |
links.receipt | string | API-relative path of its receipt (GET /tenant/operations/{uid}/receipt). |
intentReference | string | The top-up's reference with the payment provider; 12 digits. |
expiresAt | string | After this instant a payment for this top-up is no longer credited. |
railCode | string | The payment provider's code the intent was issued on. |
payerInstructions | string | null | Instructions 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.