Skip to main content
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
API reference: Positions · Report. Opens on the public documentation site in a new tab. Where it disagrees with this page, this page is authoritative for the partner surface.

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

Not yet published. There is no authoritative per-field definition for capitalRequirement, excessCapital, buyingPower, unsettledFunds or marginRequirement, and no statement of which fields overlap.Compose the rules below rather than picking a single field, and confirm the definitions with your integration lead before you expose any of them to a user.

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:
[VERIFY] — this formula is not computable from the API as written. Its first term, collateral locked by open orders and positions, has no readable source: no field we return exposes it, and whether an open short even carries a standing collateral requirement is unanswered.So do not present the formula as something you can evaluate. What you can evaluate today is min(balance − your accrued fees, buyingPower, excessCapital); the collateral term has to come from your own order and position store, as an estimate you hold back. The code below leaves that term out and says so, rather than pretending a field supplies it.
Two consequences of that composition. First, the accrued-fee term is yours: the platform never knows your fee basis, so no field we return has it subtracted — see Vendor fees. Second, taking the minimum against both platform ceilings is deliberate: while the authoritative definition of 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:
That reserve is yours to hold. An open short carries an obligation of up to $1.00 per contract, so reserving the full dollar per short contract is the only figure that cannot under-reserve. At the pool level, sweepable cash is the sum of 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.
Not yet published, and it is a money risk. Whether an open short carries a collateral requirement, and where that requirement is exposed, is unanswered. balance_reservation and margin_requirement both came back empty on the ledger entries for an open short, and two sources disagree on whether a requirement exists at all.If you gate withdrawals on a platform field alone, you will let a user withdraw the funds backing an open short. Hold the $1.00-per-contract reserve in your own ledger until you have a written answer.

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.
[VERIFY] — two things the workaround depends on are not published. The replay phase’s ordering is not stated, so “the newest entry” cannot be identified from the API contract, and there is no published signal that the replay phase has ended.The code below keeps the last entry the replay phase delivers and treats a quiet stream as the drain. Confirm both with your integration lead before you show the figure to a user.

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.
Not yet published. There is no rate limit published for GetFundingAccountBalance; the only guidance on record is “poll at modest rates”.Until it is published, poll the pool on a fixed schedule rather than per user action, and stay inside the per-firm unary budget of 250 requests / 60 s per firm that applies to your gRPC reads.

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.
Response on a firm account, with the fields you branch on:
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 one VENDOR_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 a VENDOR_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, read commission_notional_collected at priceScale × fractionalQtyScale, not at priceScale. Reading it at priceScale turns a 0.01feeinto0.01 fee into 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 0.01,not0.01, not 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 is order.clord_id. Key your accrual rows on it and join the report to them on it.
Not yet published. The report’s column specification is not published.Build your reconciliation to join on clord_id and to tolerate columns you do not recognise. Ask your integration lead for the column list and a sample file before you write the parser.
The fee-collection loop has no defined channel today. The daily Vendor Fees report has no delivery mechanism — the specification says “Delivery method TBD”. There is no endpoint, no bucket and no stream that hands you the report, so the reconciliation step of this lifecycle cannot be automated end to end yet.What to do in the meantime: treat your own accrual ledger as the collection basis, collect on your own schedule with VENDOR_FEES transfers, and keep every accrual row joinable on clord_id so that a retroactive reconciliation is possible the day delivery exists. Agree the interim delivery with your integration lead in writing before go-live, and do not plan a launch around an automated report you cannot yet receive.

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.
  • GetAccountBalance on a firm account — the six-field read.
  • The newest balance-ledger entry’s afterBalance on a participant clearing account, because GetAccountBalance returns InvalidArgument: invalid account there.
The balance-ledger stream is the system of record for cash movement. Every movement you apply comes from a ledger entry, not from a read. It delivers a replay phase followed by a live phase, so a subscription that starts mid-history catches up before it goes live.

The pool identity

Close every run on this identity:
Only 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.
Not yet published. Whether an inbound wire credit to your funding account appears as a balance-ledger entry, or only as a change in GetFundingAccountBalance, is not published.Until it is confirmed, take your wire credits from your bank’s records and treat the pool read as the check on them rather than the source of them.

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 the afterBalance 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

There is no scalable push channel for cash today, and that is a platform gap, not a configuration you can tune. The balance-ledger stream is per account, and it counts against the cap of 20 concurrent streams per firm shared across every gRPC subscription you hold — drop copy, position change and market data included. Twenty accounts is not a partner-scale number, so the ledger stream cannot be run per participant.The firm-level ledger stream does not exist. It is “coming soon” with no date.The consequence to plan around: RESOLUTION credits land in participant accounts with no push channel that scales to your account count, so settlement-driven balance changes have to be discovered by targeted reads.

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.
The entry you branch on, with the two fields the loop needs:
Not yet published. The resume field on the balance-ledger subscription, the ledger entry’s id field, and the signal that the replay phase has ended are not published.The loop above keeps the checkpoint in your own storage for that reason, which is the right design either way. Confirm the field names against your proto copy before you compile.

What can go wrong in a run

These rows stay with the procedure above rather than in the page’s consolidated table, because each one is a failure of this loop specifically.

What can go wrong

Next

Instruments and money on the wire