Prerequisites:
- the
read:reportsandread:cash-movementsscopes granted against your client — ask for both at the scopes gate, not later. See Path to production, - Funds handling — several reports are balance reports and the balance fields need reading carefully,
- your firm strings and your IB anchor DCO account — see Firms, participants and accounts.
Reporting pack
Start this in week one. Several of the ten reports below have no platform source today, and the gap between “we can pull that” and “nobody has built that” is what moves an IB’s go-live date. ISVs never ask for this pack. It exists because your registration requires it, so the questions below arrive in our channel from IBs and nowhere else.The pack
Five pieces, of which the reports are the largest:- The NFA/CFTC demo of your system.
- Flow of customer funds — where money sits at each step, which for you is constrained by the prohibition on accepting or holding customer funds.
- A back and middle office overview.
- A risk-monitoring overview — intraday, overnight, limits and thresholds, and liquidation.
- Ten named reports.
The ten reports
“What we can supply today” below is the platform surface, not a report product. We do not produce these reports for you; where a source exists, you build the report from it.Reporting mechanics that break IB reports specifically
These are the four that produce tickets.POST /v1/report/trades/search unfiltered hits the 30-second CloudFront 504 about two thirds of the time. The same call with a symbol filter returns in ~130 ms, reliably. There is no documented bulk-export path, no published window limit and no async report job, so a month-end pull is a loop over symbols, not one call.
Stored execution history is archived during maintenance, and pre-maintenance execution queries return empty. This is a material retention fact that appears only in the changelog. Maintenance is not the stable window the FAQ describes: August–September 2026 ran near-weekly one-off windows at 2–8am, 3–7am, 4–7am and 5–8am ET. Pull and persist your own copy of every traded day’s executions on the day. If your statement generation reaches back across a maintenance window, it can come back empty rather than wrong, which is harder to notice.
GetTradeStats does not behave the way a reporting engineer expects. bars is a divisor, not an interval — 6 bars over 14 days gives 2.8-day buckets. Empty buckets are returned, not omitted, as an all-zero object, so treat zero as “no trades”, never as a print at price 0. cleared_* counterparts reflect post-clearing state and read zero for recently executed trades. Use where_clause, not field_filter: field_filter validates against a fixed column allowlist that excludes update_time and create_time, so a time cursor there returns InvalidArgument: field not allowed. Page tokens are offset-based, so dedupe on symbol when sweeping pages.
The push channel does not scale to a customer book. The balance-ledger stream is per-account and counts against the 20-concurrent-streams-per-firm cap, so it cannot be run per customer. The firm-level ledger stream is “coming soon” with no date. That leaves no scalable push channel for RESOLUTION entries at scale — poll and reconcile instead.
The reconciliation mistake this causes is specific: the most common one is using raw order_qty as the contract count. On an instrument with fractional_quantity_scale = 100 that overstates the fee 100×. Instruments with scale 1 make the naive arithmetic accidentally correct, so the error often surfaces only on the first fill in a scale-100 market. One dollar is priceScale × fractionalQtyScale notional units: when both are 100, commission_notional_collected = 100 means 1.00.
Also relevant to any report that reaches settlement: RESOLUTION ledger entries may be gross with COMMISSION deducted separately, or net, and that is unanswered. Executions fold commission into a single net ORDER_EXECUTION entry, so do not assume settlement behaves the same way.
Risk-monitoring overview
The pack requires you to describe four things: intraday risk, overnight risk, limits and thresholds, and liquidation. Three constraints you can state from the platform’s actual behaviour, because they shape your own risk model:- Your order surface is fill-or-kill only and you are always the taker. You cannot rest an order, so you cannot manage risk by working an order; every order is prefunded with an exact atomic transfer and either crosses or expires.
- **An open short carries an obligation of up to 1.00 per open short contract in your own model until the field is named.
- Day orders cancel at the traded-day roll as of 2026-09-13 (v0.0.89); GTD is the alternative. This does not apply to the fill-or-kill partner surface, but it applies to any generic order-entry question your reviewer asks about.
The NFA demo
The demo requirement is real and the environment question is not settled, because preprod cannot demonstrate a settled market.What can go wrong
Naming and record requirements
Three record-level mistakes break IB reporting, and all three are cheap to prevent and expensive to unpick after go-live. Check every production record against this section before your first customer.The legal name must be a physical person’s name
At the account level and at the user level, the legal name must be a physical person’s name, or NFA reports error. Not your company name, not a DBA, not a product name, not “Operations”. One partner’s production record was entered as the company name. This is an internal SOP gap on our side as much as a partner-facing rule — nothing validates it at entry, so the failure surfaces later, in a report, against a record you can no longer casually change. What to check, per record, before production traffic:- The account-level legal name is a natural person’s full legal name.
- The user-level legal name matches that person’s government identity, not a display name from your app.
- No record carries your firm’s name, a team name, or a test string.
- Your own customer row stores the
participantIdwe issued, verbatim, so the mapping back to the record is unambiguous.
Address format
The one published constraint is narrow:postal_code is five digits. A nine-digit ZIP+4, a hyphenated form or a non-US postal code will not satisfy it.
Related field constraint on the same payload: external_id is capped at 49 characters.
There is also no authoritative excluded-states or jurisdiction list in our docs. One partner
asked three times and was never answered.Do not infer eligibility from the address fields you collect.
participantType casing, per path
This is a live defect, and the IB path is the accidental beneficiary of it.
introducing_broker is spelled identically in both vocabularies. The IB path has therefore only ever worked by orthographic accident — not because the create path handles IB correctly, but because there is no casing difference to trip over.
Canonical casing to send, per path:
- Create: send the vocabulary spelling the create path validates against, exactly. For an IB that is
introducing_broker; do not assume the uppercase transformation that ISV requires applies to you, and do not experiment on a production create. - Adopt and provision:
introducing_broker. Anything you send is lowercased, so this is the spelling that survives.
Do not confuse the DCO clearing-member ID with the DCM firm name
You hold three identity strings, and two of them look interchangeable and are not.
Confusing a DCO clearing-member ID with a DCM firm name has stalled an onboarding outright. The failure is on our side, triggered by the record mismatch, and no error is returned to you — onboarding simply does not complete. Expect diagnosis to take time, so give us the identity strings up front.
Record all three strings verbatim at your credential gate, label them in your own configuration by what they are rather than by which page you got them from, and never construct one from another.
provisionedAccount, the fully-qualified DCM account name, is separately opaque: its account identifier cannot be derived from participant or user data.