Wallet & billing
Fabric bills from a prepaid wallet. Every message reserves funds before it is sent and settles after, so cost is always tied to a delivery you can reconcile.
Money is minor units, as strings
Section titled “Money is minor units, as strings”Fabric represents money as integer minor units — pesewas for GHS, kobo for NGN, cents for USD — and the SDK returns them as strings so JavaScript never rounds a balance or a cost.
const money = { minor: "12050", currency: "GHS" }; // GHS 120.50Never parse a minor value into a float for arithmetic. Do integer math on the string, or use a
decimal library, and format for display only at the edge.
Read the wallet
Section titled “Read the wallet”const wallet = await fabric.wallet.retrieve();
const ghs = wallet.data.balances.find(({ balance }) => balance.currency === "GHS");console.log(ghs?.balance.minor, ghs?.balance.currency);console.log(ghs?.lowBalanceThreshold?.minor);balances holds one entry per currency, each with a balance and an optional lowBalanceThreshold.
ledger holds recent movements — each a type (topup | sms_charge | refund | adjustment), a
direction (credit | debit), an amount, and a runningBalance.
Reservation and settlement
Section titled “Reservation and settlement”- On send, Fabric reserves the message cost against the wallet.
- On a terminal state it settles: a delivered message is charged; a message that fails or expires is refunded to the wallet.
- Each provider attempt records its own
coston the delivery’sattempts[].
The money path fails closed
Section titled “The money path fails closed”Unlike the control-plane checks that fail open to keep the data plane alive, the wallet path fails
closed: if funds cannot be reserved, the send is refused with insufficient_funds (HTTP 402),
not sent on credit. Sandbox sends never consume real funds — they exercise the same reservation logic
against sandbox balances so your cost handling is correct before you fund live.