Wallet Balance
Wallet Balance answers a different question than the Ledger does. The Ledger is Ishtaran's own economic accounting — Available, Pending, Reserved, Payable, Delivered — populated exclusively by real Payment/Settlement/Payout flows. Wallet Balance is an observation of chain state: how many tokens actually sit, right now, at an Account's registered self-custody address. Simulated in Sandbox, real on-chain in Production.
Never sum the two, never substitute one for the other. An Account can have a large Ledger
Payable and a Wallet Balance of 0 at the same time — nothing has been paid out on-chain yet.
Or a wallet can hold funds the Ledger has no opinion about at all — its owner moved money in from
outside any Ishtaran-mediated flow entirely.
A concrete example
Say an Account's wallet holds 100 USDT on-chain right now (Wallet Balance), while its Ledger shows Payable: 30, Reserved: 10, Delivered: 25 from unrelated Settlement activity. These are five separate numbers answering five separate questions — never add them together, and never report one as if it were the other:
| Field | Source | Question it answers |
|---|---|---|
| Wallet Balance: 100 USDT | Observed chain state | "How many tokens sit at this address right now?" |
| Ledger Payable: 30 | Settlement (not yet paid out) | "How much has Ishtaran settled to this Account but not yet moved on-chain?" |
| Ledger Reserved: 10 | Transaction reserve (in flight) | "How much is locked against a Transaction still in progress?" |
| Ledger Delivered: 25 | Payout (already moved on-chain) | "How much has Ishtaran already paid out to this Account historically?" |
A Wallet Balance of 100 does not mean 30 of it is "the Payable"; the wallet may hold that 100 from a completely unrelated deposit, an earlier Payout, or funds moved in from outside Ishtaran entirely. Conversely, a Payable of 30 does not mean the wallet is guaranteed to show +30 once paid out — on-chain timing, network fees, and partial payouts all mean the two numbers move independently. Show both, labeled separately, never merged into one displayed balance.
Why this exists
Every Account with a registered ExecutionDestination already has a real, addressable wallet —
Self-Custody requires one before any Settlement leg can execute. Wallet Balance
answers the question that address itself always implicitly raises: "how much is actually there?"
— without requiring a Settlement, a Withdrawal, or any other Ledger-affecting event to have
happened first.
Reading a balance
- Snapshot read —
GET /v1/accounts/{accountId}/wallet-balancesreturns the platform's last known observation: the address, the balance, when it was last observed, and whether that observation is stale. This call never itself queries the blockchain — safe to call on every page load. - Authoritative refresh —
POST /v1/accounts/{accountId}/wallet-balances/refreshasks the platform to check the real chain state right now. The platform enforces its own short (~30 second) freshness/single-flight guard server-side — calling this more often than needed is always safe, never an error, never extra provider cost. Check the response'sstale/refreshSuppressedfields to see whether a real check actually happened. - Multi-asset aggregate —
GET /v1/accounts/{accountId}/wallet-balances/aggregatesums balance across several AssetNetworks the caller already knows about (for example USDT across multiple networks), grouped by Asset, with a per-network breakdown in the result. Never sums across different Assets.
Kept fresh automatically
The platform keeps a wallet's balance current on its own — a Settlement, Payout, or Withdrawal confirming under Self-Custody triggers an event-driven refresh for the affected address, alongside a periodic background reconciliation sweep. A client does not need to poll aggressively for correctness.
A client MAY independently observe a real chain itself (Production only — there is no independent chain to read against in Sandbox) as a cheap, optional signal for when to call the refresh endpoint sooner. That observation is only ever a hint: the platform always re-verifies for itself and never accepts a client-reported balance as authoritative.
Send vs Pay
Both move funds out of a wallet, but they mean structurally different things to the platform:
- Send is a direct, sender-initiated wallet-to-wallet transfer. It never creates a Transaction, PaymentIntent, or Settlement — it's a peer paying another peer, full stop.
- Pay is the fulfillment of an existing Payment Request (a PaymentIntent tied to a specific Transaction). It drives the real Transaction → PaymentIntent → Settlement pipeline described in Transaction, Settlement, Split, and Refund — Split, Fee, and Ledger accounting all apply the way they do for any other Settlement.
A request to preview what a payment will cost (fees, recipient amount) should never, by itself, create anything real — no Transaction, no PaymentIntent. Only an explicit confirmation should move to Pay's real pipeline.
Receive
Receiving is not a distinct capability so much as two different things an Account can do:
- Accept a direct Send — nothing to set up in advance; any registered self-custody address can receive a transfer.
- Issue a Payment Request — create a PaymentIntent ahead of time (an amount, an optional description, an expiry) so a payer can fulfill it via Pay. The payer never needs an account relationship with the requester beyond the shared Transaction the request represents.
Routes
- Get balance (cheap, cached):
GET /v1/accounts/{accountId}/wallet-balances - Refresh balance (authoritative, guarded):
POST /v1/accounts/{accountId}/wallet-balances/refresh - Aggregate across AssetNetworks:
GET /v1/accounts/{accountId}/wallet-balances/aggregate