GetAccountBalance returns six money fields and none of them is named “spendable”. This page gives you the rule for cash a user may spend, the fee accruals only you can see, and the daily run that proves both.
Before this page
- You can mint an access token and hold the account-scoped read grants — see Authentication.
- You know which firm each account belongs to — see Firms, participants and accounts.
- You can move cash and you know that direction is fixed by the reason — see Move cash.
- You know the residue you cannot move — see Sub-cent balances.
- You can open a balance-ledger subscription — see Balance ledger.
Which number is spendable
If you are an IB, this differs.
These fields feed two of your named reports, Equity Run / Account Status and
Margin Call / Debit, so the
InvalidArgument: invalid account failure on participant
accounts is a reporting blocker for you rather than a curiosity — see
Reporting pack. Treat the open-short collateral question as a
stated control: hold back $1.00 per open short contract in your own model and say so in
your risk-monitoring overview.The six fields
Spendable cash
Three different definitions are in circulation across three current pages. Each one covers a real term and none is complete on its own. The real gate composes all three:
Use this, and only this:
buyingPower and excessCapital is unpublished, the lower of the two is the only value that cannot overstate what a user may spend.
Withdrawable and sweepable cash
Withdrawable cash is spendable cash minus what is backing obligations you have not closed:withdrawable across your participant accounts, moved out one WITHDRAWAL transfer at a time. Nothing sweeps itself: settlement credits and released collateral stay in the participant’s clearing account and become buying power there.
The read that fails on participant accounts
GetAccountBalance returns InvalidArgument: invalid account for a participant clearing account, while the same call succeeds for a firm account. This is a platform gap, not a malformed request, and no amount of reformatting the account name fixes it.
There is no point-read RPC for a participant account balance. No RPC returns one entry, or one field, for that account: the balance ledger is a stream with a replay phase and then a live phase, and the workaround is to subscribe, let the replay phase drain, and take the newest entry’s afterBalance.
Be clear about what you are accepting: a ledger scan standing in for a one-field read, with a per-account stream that counts against your firm’s cap of 20 concurrent streams. The read budget and the reason this does not scale per participant are under Reconciling cash.
The pool
GetFundingAccountBalance is the pool’s source of truth. Reconcile your own view of the pool against it, not against the sum of your participant balances.
Read a balance
The channel and the per-call metadata below come from the canonical client published on
Authentication.[VERIFY] — the owning service and fully-qualified method names for
GetAccountBalance,
GetFundingAccountBalance and the balance-ledger subscription are not published, so the stub names
in the snippets are placeholders.Read the real names out of your own proto copy before you compile.Only the field names and
balance are real here. 1377.57275 is an observed production balance,
shown because it is the reason this surface needs Sub-cent balances;
the other five values are elided rather than made up, because no published relationship between them
exists yet.These money fields arrive as JSON strings. 1377.57275 is not an int64 — the
“int64 serializes as a string” rule belongs to the scaled integer fields on the order and
execution surfaces, not to this response. Either way the handling is the same: parse money into a
decimal type, never into a binary float you then round. 1377.57275 is not float-safe.Vendor fees
You charge your own fees, you track every accrual yourself, and you collect with oneVENDOR_FEES transfer per participant account. The accrued-fee total this section produces is exactly the fee term in the spendable rule above, which is why the two cannot be built independently. This section also assumes you carry order.clord_id on every order you place — see Place an order.
The platform does not know your fee basis
We never know your fee basis, and accrued-fee tracking is not exposed on any endpoint or stream. No field we return has your fees subtracted, no report we generate computes them, and there is no accrual balance to query. Every number in this lifecycle is one you compute and store. Your fee basis lives in your Fee Agreement, which is not public and is sent during commercial discussions. It is not discoverable through the API.The lifecycle
1
Declare
Agree your fee basis with us in the Fee Agreement, alongside the Vendor Connectivity Agreement.
Nothing about this step touches the API surface.
2
Accrue
On every fill, compute the fee and write an accrual row keyed on
order.clord_id. clord_id is
required by the runtime on CreateVendorOrder, so you always have one; generate it yourself
and store it before you place the order, because it is the only key that will join your accruals
to our report.3
Report
Reconcile your accruals against the daily Vendor Fees report. See the blocker below.
4
Collect
Move the accrued amount out of the participant account with one transfer, reason
VENDOR_FEES,
direction participant account → your funding account. Amount is capped at two decimal places, so
truncate toward zero and carry the remainder forward — see Sub-cent balances.Accrued fees are your credit exposure
Between accrual and collection the cash sits in the user’s participant account, and the user can spend it on a trade or take it out with a withdrawal. Nothing on the platform reserves it for you. Every uncollected accrual is unsecured credit you have extended to that user. Two rules follow. Hold a shadow balance per participant account. Your shadow balance is the accrued, uncollected fee total for that account, and it is the fee term subtracted in Spendable cash — the platform never supplies it, so an account’s spendable figure is wrong by your whole shadow balance if you leave it out. Collect on a schedule short enough to bound the exposure. The longer the gap between accrual and aVENDOR_FEES transfer, the larger the balance a user can withdraw out from under you.
Getting the accrual arithmetic right
If your fee basis is derived from the exchange commission on a fill, readcommission_notional_collected at priceScale × fractionalQtyScale, not at priceScale. Reading it at priceScale turns a 1.00 on a 32-cent trade, which has already exceeded a real customer’s entire prefund and suppressed their refund. One dollar is priceScale × fractionalQtyScale notional units, so with both at 100, commission_notional_collected = 100 means 1.00.
Two further facts change fee models built on exchange fees. Your surface is fill-or-kill only, so you are structurally always the taker and can never earn the maker rebate — the taker coefficient is the only rate you will ever pay. And the taker coefficient Θ changed from 0.06 to 0.0695 on 2026-09-14 with no fee-schedule endpoint to read it from, so every partner hand-edited their systems. A fee basis expressed as a multiple of exchange fees needs a hand-edit path and an owner.
The daily report
The join key isorder.clord_id. Key your accrual rows on it and join the report to them on it.
Reconciling cash
Reconcile your pool and every participant account once a day against the balance ledger, with a checkpoint you resume from rather than re-read. A run needs both halves of this page: the balance figures above are what you anchor on, and your own accrued-fee ledger is what explains the cash the platform cannot account for.Anchors and the system of record
Two different kinds of number go into a reconciliation, and mixing them up is how a run double-counts. Anchors are point-in-time reads. You take them once, at the start of a reconciliation series, and then never again unless you have lost your checkpoint:GetFundingAccountBalance— the pool’s source of truth, and the only authoritative pool figure. Do not substitute the sum of your participant balances.GetAccountBalanceon a firm account — the six-field read.- The newest balance-ledger entry’s
afterBalanceon a participant clearing account, becauseGetAccountBalancereturnsInvalidArgument: invalid accountthere.
The pool identity
Close every run on this identity:CONFIRMED movements belong in those sums. PENDING and AMBIGUOUS movements are the residual: carry them as in-flight, name them in the run, and do not net them into either side. A run that does not close is either missing an in-flight movement or missing a wire credit.
A restart is not a cold start
When your reconciliation process restarts, resume from your checkpoint. Do not re-run the anchor reads. Re-anchoring is not a harmless refresh: it discards in-flight movements, re-applies ledger entries you have already applied, and produces a break that looks like a platform problem. A checkpoint is per account: the last ledger entry you applied, plus theafterBalance you derived from it, plus your in-flight movement list keyed by idempotency_key. Write it in the same transaction as the ledger entry you applied. Anchor reads happen exactly twice in the life of an integration — at first run, and after you have genuinely lost the checkpoint.
The structural problem
The interim pattern
1
Spend your stream slots deliberately
Subscribe the balance ledger for your highest-turnover accounts only, and keep the total across
all gRPC subscriptions under 20 per firm. Decide the split between drop copy, position change
and ledger streams once, in writing, and hold a slot in reserve for reconnects.
2
Poll a targeted set, not every account
You already know most of the accounts that changed: you initiated every transfer, so the accounts
you touched since your checkpoint are exactly the accounts whose cash moved. Add accounts holding
positions in instruments that settled. Poll that set, not your whole roster.
3
Size the poll against the unary budget
Your gRPC unary budget is 250 requests / 60 s per firm, shared across every unary call your
firm makes, and there is a second per-endpoint rung on top of it. One read per account per cycle
means your cycle cannot be shorter than
accounts ÷ 250 minutes if reads are all you do — so
5,000 accounts cannot be swept inside 20 minutes, and cannot be swept at all if the same budget
is carrying your trading reads. Budget the sweep first, then give the remainder to everything else.4
Reconcile the rest daily, not continuously
For accounts outside the polled set, one read per day is the pattern. Ledger CSV downloads are
limited to about 5/min per firm, so a bulk daily pull is a scheduled job with retries, not a
fan-out.
The loop
There is no
curl tab here: the balance ledger is a gRPC stream and there is no REST equivalent. The
command-line path is grpcurl with a local proto file, which is a debugging aid rather than a
reconciliation process — it has no checkpoint.