Wallet
Invoices & Bill Pay

Invoices & Bill Pay

Who calls these endpoints?Portal / SDK
Base path
/api/portal/v1/wallet/me
Identity
Publishable key (pk_live_…) → OTP → customer session. The session belongs to the end user, not to the merchant, and reaches only that user's own data.
Authorization
The session itself is the authorization; a user reaches only their own record.Step-up: for money-out actions the session alone is not enough; an OTP code or a trusted action token is required.
Cross-surface
The s2s API has NO invoice or bill-payment endpoint. The payment flow lives on the portal, invoice ISSUE and cancel in the panel (POST invoices, POST invoices/:id/cancel — wallet:invoice:manage), and monitoring also in the panel (GET invoices, GET bill-payments — wallet:operation:read).

Two similar-sounding but distinct capabilities:

CapabilityWhatPaid to
InvoiceA business inside the program invoices a userA business inside the program
Bill payPaying a utility/telecom billAn external biller

In-wallet invoices

Coming soon

The contract for issuing, listing and paying invoices from the wallet is complete. It is awaiting release; these endpoints do not accept requests today. Status: Roadmap.

Issue an invoice

POST /api/panel/v1/wallet/invoices
FieldTypeRequiredDescription
issuerAccountIdstring✅Business account issuing the invoice
currencystring✅
linesarray✅Items: description, quantity, unitAmount
totalAmountstring—Computed from lines when omitted
payerWalletNostring⚠️Wallet number of the payer
payerPhonestring⚠️Phone of the payer
externalInvoiceNostring—Your invoice number
dueAtIsostring—Due date
notesstring—

⚠️ One of payerWalletNo or payerPhone is required.

If you omit totalAmount it is computed from the lines. If you send both they must be consistent — avoid rounding drift by doing minor-unit integer arithmetic.

The user sees and pays it

GET  /api/portal/v1/wallet/me/invoices
GET  /api/portal/v1/wallet/me/invoices/{id}
POST /api/portal/v1/wallet/me/invoices/{id}/pay

Payment comes from the wallet balance and may require OTP/step-up.

Webhooks

EventWhen
wallet.invoice.issuedInvoice issued
wallet.invoice.paidInvoice paid
wallet.invoice.cancelledInvoice cancelled

Bill pay

Coming soon — requires a biller integration

Inquiry, payment, status tracking and reconciliation are built. To run in production a biller integration must be connected: biller codes and debt inquiry come from it. Without one, these endpoints do not accept requests. Status: Roadmap.

Inquire the debt

POST /api/portal/v1/wallet/me/bills/inquire
FieldRequiredDescription
billerCode✅Biller code
subscriberNo✅Subscriber number

The inquiry returns the amount due and, when available, the due date.

Pay

POST /api/portal/v1/wallet/me/bills/pay
FieldRequiredDescription
billerCode, subscriberNo✅Values from the inquiry
sourceWalletAccountId✅Account to pay from
amount, currency✅
billRef—Debt reference from the inquiry
billerCategory—
idempotencyKey✅Double-payment protection
trustedActionToken—Step-up

Track

GET /api/portal/v1/wallet/me/bills

Statuses and reconciliation

Because bill pay depends on an external institution, it settles asynchronously:

EventMeaning
wallet.billpay.dispatchedInstruction sent to the biller
wallet.billpay.confirmedThe biller confirmed the payment
wallet.billpay.failedThe biller rejected it; funds returned
wallet.billpay.awaiting_reconOutcome uncertain, sent to reconciliation
wallet.billpay.reversedA confirmed payment was reversed
⚠️

dispatched does not mean "the bill is paid". Tell the user "sent"; use "paid" only on confirmed. Otherwise, when the biller rejects, the user believes they have paid.

⚠️

Never retry a bill payment sitting in awaiting_recon — it may already be paid on the biller side. Wait for reconciliation.

Common mistakes

SymptomCauseFix
Inquiry returns nothingWrong subscriber number or biller codeShow a per-biller format hint to the user
Payment stuck in awaiting_reconThe biller's response was inconclusiveWait; do not pay again
Bill amount differs from paid amountA partial payment was attemptedWhether partial payment is allowed depends on the biller integration