2026-09-28: The margin preview gives a verdict on the paper book
POST /api/trading/margin-preview on a paper book account, a Demo included, now answers with the
margin the order adds under the account’s risk policy and a real sufficient verdict. The paper book
refuses an order that adds exposure when its margin, plus the commission of an order that fills now,
doesn’t fit the account’s free collateral. The preview judges the order the same way at the moment you
ask, so sufficient: false means that order would be refused now. Before this change the preview
answered sufficient: null and described its figure as an estimate nothing enforced.
estimate stays true, because the price and the free collateral can change before your order
arrives. marginRequired and sufficient are null when there’s no verdict: there’s no price, a
position can’t be valued, the risk policy doesn’t cover the instrument, or the order would be refused
for another reason first. basis names the risk policy version the figure comes from, or says why
there’s no verdict. A risk lock and your size limits aren’t judged by the preview.
What it asks of your integration: if your interface ignored sufficient on the paper book, start
reading it. Block or warn on false, as you already do for other providers. A stop-limit order’s
preview reads its limit from limitPrice.
2026-09-28: Every risk lock says whether you can clear it
Every risk lock now carriesclearable: in lock on GET /api/risk, PUT /api/risk and
POST /api/risk/unlock, and in each lock event on /api/account/stream. It’s true when
POST /api/risk/unlock would clear the lock now, and false while the settings are locked, for a
failed evaluation, a firm halt or a drawdown rule, and for any lock that holds trading on an account
bound to a risk policy. It’s true while nothing is locked.
The field is additive. An integration that decided from lockReason whether to offer a way to clear
a lock reads clearable instead, and offers it only while tradingLocked and clearable are both
true. The unlock answers every call as it did before.
2026-09-28: Every venue response is the documented venue record (PREVIEW)
POST /api/operator/venues and POST /api/operator/venues/{venueId}/firm answered with the venue as
it is stored, internal fields included (companyId, creationKey, creationHash and the stored
switch), where the reference documents a VenueRecord. The venue read and the venue rules switch
served the same internal fields beside the record’s own. Every route that answers a venue now answers
exactly the VenueRecord: id, organizationId, legacyFirmId, name, description,
environment, state, version, createdAt, rules and company. An integration that read
companyId from one of these responses reads company.id.
2026-09-28: Level 2 is now venue rules (PREVIEW, breaking)
The venue’s switch for its own order limits, stages and analytics is now called venue rules, since “Level 2” reads to a trader as market depth. The meaning and the request body are unchanged; three names move, with no alias:- The switch is
POST /api/partner/venues/{venueId}/rulesand, for the back office’s signed-in session,POST /api/operator/venues/{venueId}/rules. The old/level2path on either answers404not_foundand changes nothing. - The venue read (
GET /api/partner/venues/{venueId}and its operator twin) and the switch’s response carry the block asrules, the same shape the oldlevel2field had:{ enabled, applies: { orders, fills, stages }, appliesAtProvider: { orders, fills, stages } }. Nolevel2field is served. - The operation’s summary is “Turn venue rules on or off”, so its reference page moved; the old
page redirects to the new one. Its request and response schemas are
VenueRulesRequestandVenueRulesResponse.
/level2 to /rules and reads venue.rules where it
read venue.level2. Nothing else in a request or a response changes.
2026-09-28: Two venue operations are documented for a Venue key
GET /api/partner/venues/{venueId}/connections/{connectionId}/accounts lists the accounts a provider
connection can reach, and POST /api/partner/venues/{venueId}/accounts/bind binds one of them to your
venue. Both answer a Venue key, the first with the account:read scope and the second with
connection:manage and account:issue. Until now the reference listed them only among the back
office’s session routes. Nothing changes for an integration that already calls them.
2026-09-28: A futures order on a Demo opens the trader’s own market data
On the paper book, a request on the trader’s own signed-in session toPOST /api/trading/order,
/close, /reverse or /flatten opens the trader’s own market-data session for a futures
instrument before the order is placed, as their chart does, and waits up to 5 seconds for it. A
trader no longer needs a chart open for a first futures order on a Demo to fill. A request with a
Trading API key opens none. When no session can serve the instrument, market_data_unavailable’s
cause says why instead of feed_down, with three new values: login_missing (no market-data login
the trader connected serves the instrument), feed_capacity (the engine could not open another
market-data session; try again shortly) and feed_displaced (another application took over the
market-data session on that login). An order that must fill now is refused with it and nothing
written; a close and a reverse are refused with it before anything is claimed or cancelled; every
other refusal of the order comes first as before; a limit or stop order still rests, and a flatten
still runs.
An order on an account whose risk decisions have not yet decided anything, such as a Demo opened a
moment ago, waits up to 1 second for the first decision before answering 423 risk_locked.
2026-09-28: An order waiting on an instrument’s first price is refused as missing market data
On the canonical book, an account whose one hold is that the price lane of an instrument it holds has delivered no price yet (a position just opened on an instrument whose lane opens only once the account holds it) refuses an order onPOST /api/trading/order that adds exposure on that instrument alone
as 422 market_data_unavailable, with params { instrument, cause: "mark_missing" } and
instrument the venue’s instrument id. It was 423 risk_locked with params.holds
["risk_uncovered"], which read as a risk setting. The order is still refused and nothing is
written; send it again once the price arrives. An order adding to any other instrument on that
account is still 423 risk_locked, and so is every addition while any other hold is on the
account (a trading lock, a drawdown or stop-out latch, a liquidation incident), once coverage is
lost after a price arrived (a gap, a stale or down source, an interruption), and every order on the
replace, reverse and exits routes. An account whose risk decisions have not yet read any price or
instant at all (its very first position, before any price arrived) can still answer 423
risk_locked there, since a risk term with an effective window or a day margin is not yet in force
for it.
GET /api/trading/actions still states the hold. Cancels, closes and reductions are unchanged.
2026-09-27: A close and its exits can name one position, and ticket accounts trade through every order route (PREVIEW)
On the canonical book,POST /api/trading/close and POST /api/trading/exits take an optional
positionId, the position’s id as the account’s positions state it, and an optional
positionRevision, the revision the trader saw. The close then fills only against that position,
never another on the instrument and never past flat, and the exits protect that position alone. The
book checks the position when the command commits: one no longer open on the instrument, held on the
side the close trades, or smaller than the close is 422 position_not_closable, and one past the
stated revision is 409 position_revision_stale, each with nothing written. A broker that names no
positions answers 400 with code position_close_unsupported or position_exits_unsupported.
On an independent-ticket account every entry opens a ticket of its own, whether it fills now or
rests: market orders, marketable limits and brackets now fill there too. A bracket’s exits close its
own ticket. A reduction that names no ticket, and exits set by instrument, are 422
position_mode_unsupported; name the ticket instead. POST /api/trading/flatten closes every ticket
on the instrument.
2026-09-27: An issued account states whether it nets or holds independent tickets (PREVIEW)
Issuing an account on the venue platform takes an optionalpositionMode: net, one signed
position per instrument and the default when the request states none, or independent_tickets,
each opening order its own position, closed by naming it and never netted against an opposite one.
Any other value is 400 invalid_request with field positionMode. A Personal Demo connect that
opens an account takes the same optional positionMode, also netting by default. Independent tickets open only under a policy
whose pool for the class states ticketHedging; otherwise the issue is 409
position_mode_unsupported and nothing is written. The issued account states its positionMode,
and a retry with the same referenceId must state the same one. Publishing a risk policy version
that states no ticketHedging for a class whose bound pools hold independent tickets is 409
risk_policy_ticket_hedging_required, and the version in force stays. A discovered provider account is
bound in the model its provider reports, net or hedged; a hedged account cannot be a hedge
destination (409 position_mode_unsupported).
2026-09-27: Every position has an identity, and every position read states the account’s position mode
positionModel on the account snapshot and every account frame is now net or
independent_tickets, and GET /api/account/positions answers it beside the rows, read with
them. The frame also carries the paper-book account’s economic cycle, which a reset advances,
so a frame of an earlier cycle is recognizably about an account that no longer exists; it is null
on a provider account. Every PositionRow on the paper book carries positionId, the ledger’s
stable, opaque id for the position, and positionRevision, the position’s own revision:
1 when it opens and one more each time an execution changes it. A net position gets a new id each time it opens, so a reversal or a reopen after flat is a new
position. On an independent_tickets account each open ticket is its own row under its own id,
with its signed quantity, entry price (avgPrice) and its own unrealized profit, so a long and a
short ticket on one instrument are two rows, never one net row. Each WorkingOrderRow names by
positionId the ticket it opens or, when reduceOnly, closes or protects, so a ticket’s exits are
the reduce-only orders naming it; on a net account a protective exit rested by a fill names the
position it protects, and other orders name none. Both fields are null on every provider’s position
and order, since trdrs never invents an identity for a provider’s position.
GET /api/trading/position answers one net position per instrument, so on a ticket account it
answers 422 position_mode_unsupported instead of a sum of the tickets. Firm account analytics
states positionModel, and each open position and closed trade names its positionId; the venue risk
desk names each position’s positionId and each account’s positionModel, and a ticket’s realized
result is its own closed trades, never its instrument’s. A net account keeps its behavior; it gains
the new fields.
2026-09-27: An immediate order is admitted again when the account moves under it
An immediate order on the canonical book reads the account and its prices, then admits itself. When another revision of the account commits in between (a funding or financing charge, a resting order’s fill, a balance operation), the engine now reads and admits the order again, up to three times, and answers409 version_conflict only when the account kept moving each time. An order states no
version of its own, so the conflict was never the client’s. A change to the venue’s configuration in
between still refuses the order at once, since it was placed on terms that no longer hold. Nothing is
written by an attempt that does not fill.
2026-09-27: An instrument of another class than the account’s pool holds is refused as its class
An order on the canonical book for an instrument whose product class is not the one the account’s pool holds (a CFD on a futures account, a future on an FX/CFD account, a perpetual on a futures account) is refused400 asset_class_not_supported, with the instrument, its assetClass (cfd,
futures or crypto) and provider paper, the code the route answers for a class a provider does
not trade. It was collateral_policy_unverified with cause contradictory, which read as a policy
fault. An account’s instrument catalog states the same refusal as the instrument’s poolRefusal.
Nothing is written either way.
2026-09-26: An imported paper account is served from the canonical book
Once the cutover imports a paper account from the Demo book, every trader route (orders, fills, positions, balances, the instrument list, competition entry) reads and writes it on the canonical book under the same account number. Its paper connection states the instant it opened on the canonical book, its import, where it stated the Demo account’s creation. A trader’s instrument list comes from the account’s venue catalog on every deployment. Its fills in the same second keep the order the ledger recorded them in on the executions route, the later one first. No field changes shape.2026-09-26: Orders on trdrs CFDs (PREVIEW)
POST /api/trading/order and the other order routes accept a trdrs CFD named by its contract id
(TRDRS:EURUSD, for example) on an account on the canonical book whose pool holds FX and CFDs,
sized in lots on the contract’s grid (qty at least 0.01, in steps of 0.01). A CFD fills at the account’s executable quote: the source’s
bid and ask rounded outward to the tick, then widened by the pool policy’s markup. Nothing fills
outside the contract’s trade session (contract_not_trading, phase session_closed), and a resting
order waits for the session. On any other account, and on every other provider, the order is refused
400 asset_class_not_supported with assetClass cfd, before anything is written. The source’s
own symbol (EURUSD) names no contract and is unknown_instrument. A commission in basis points on a
CFD quoted in another currency than the account’s (TRDRS:USDJPY in a dollar account) is converted
into the account’s currency at the fill, at the side worse for the account; with no conversion quote
in force the order is refused collateral_unvalued with cause conversion_unavailable or
conversion_stale, and nothing is written.
2026-09-26: collateral_unvalued names a conversion it could not price
Thecollateral_unvalued refusal’s cause has two new values: conversion_unavailable and
conversion_stale. Each says the requirement of the order’s instrument is stated in another asset
than the account’s currency (a currency pair’s margin, in its base currency) and the conversion that
carries it into the account’s currency has no usable price, or only one older than its route allows.
instrument names the instrument whose requirement needed it. Nothing was written. A requirement is
converted at the side that makes it larger, so a wider spread never lowers it.
2026-09-26: Personal Demo version 2026-09-26.3 states its fill terms: no commission and no markup
Personal Demo policy version2026-09-26.3 succeeds the unpublished 2026-09-26.2 and, like it, is
in force only once trdrs publishes it. Its only change is a fill term in both its futures and its
crypto derivative pool, demo-execution-2026-09-26.3: no commission, no markup, and a collar of no
ticks, each a trdrs term with its reason, the commission counting contracts in the futures pool and
base units in the crypto derivative pool. A policy’s pool may state such a term (execution: the
commission, the markup as bidTicks and askTicks as a CFD pool’s markup rows state it, and the
collar, each figure sourced) only when the policy is trdrs’s own; a
firm’s accounts fill on its venue’s conditions, and a firm policy stating execution is refused.
2026-09-26: Analytics and stage eligibility read the stage the cycle is judged by (breaking)
An account’s analytics and stage eligibility no longer take their session or stage rules from the request. They measure against the stage version the account’s running cycle is judged by, as its venue published it.GET /api/partner/accounts/analyticsandGET /api/partner/accounts/eligibilityno longer taketimeZone,rolloverHour,stageId,profitTargetorminimumTradingDays; a request that sends them has them ignored. Trading days are counted in the stage’s session, or in the 17:00 America/Chicago roll for a cycle no stage judges, andtradingDays.sessionstates which.- The eligibility check states the stage it measured in
stageand answers409stage_unstatedfor an account whose cycle no stage judges. The legacy door issues into a group running no stage, so its accounts answer that; the venue’s stage eligibility route is the check for staged accounts. - The venue analytics route (
…/venues/{venueId}/accounts/{accountId}/analytics) and the venue risk book (…/venues/{venueId}/risk) no longer taketimeZoneorrolloverHour; each account’s days are counted in its own cycle’s stage session.
2026-09-26: A commission states its timing, direction and unit (PREVIEW, breaking)
Every commission a condition profile, group override or preview states now requirestiming
(fill, charged as each fill lands, or round_turn, nothing on the entry and the stated round-turn
amount on the quantity each reducing fill closes) and direction (entry, exit or both; a
round_turn commission is stated with both, else 400 round_turn_is_both), and a perUnit
commission requires unit: "quantity": the amount counts each unit of the instrument’s own
quantity unit, since the conditions cover every instrument. A venue that charges its product classes
different per-unit rates states each through a group of its own. A write that omits a field is
refused 400 with field naming it. Every stored profile and group states timing: "fill",
direction: "both" and, per unit, unit: "quantity", which is what it always charged, so no
account’s charges change. venue_fill_refused gains the reason commission_unit_mismatch, for a
per-unit commission a term scopes to contracts, lots or base units on an instrument counted in
another unit.
2026-09-26: A CFD’s financing comes from the venue’s published risk policy (PREVIEW, breaking)
A condition profile, group override or preview that statesfinancing is refused with 400 financing_superseded, field naming it, as margin is: a venue’s financing is the financing
term of its published risk policy version, which states each CFD’s long and short annual rates and
the rollover rule it is financed on, either value dates on a business-day calendar or a multiplier
for each weekday (three on Wednesday, for example). The conditions’ financing field is removed from
VenueConditionProfile and VenueGroupOverride, and removed from every stored profile and group; no
financing was ever charged under it. A CFD position on the canonical book is financed once at each
rollover of its row’s rule, at the executable side worse for the account (the ask when the rate
charges, the bid when it credits), in its profit asset, converted into the pool currency along the
pool’s declared route; a charge whose price or conversion quote is not journaled at the rollover is
owed with an unknown amount, never zero, and holds the account’s additions until it is priced. The
analytics fields that count financing are unchanged.
2026-09-26: Canonical analytics and the venue risk book state money exactly, half to even
An account on the canonical book states its analytics money (realized profit, fees, net trading, balance, unrealized profit, equity and each closed trade) computed exactly and rounded once, at the precision the canonical book’s posting term states for the account currency, half to even. A value on a tie, such as an equity of 50,070.625, is stated as 50,070.62 where it could before be stated as 50,070.63. The venue risk book sums money the same way per currency, so a USDC book’s totals, notional, exposure and history carry all six decimals where they were stated in cents, and exposure money across more than one currency isnull. No field changes shape.
2026-09-26: An issued account’s pool may hold FX and CFDs (PREVIEW)
POST /api/partner/venues/{venueId}/accounts accepts riskPolicy.profile fx_cfd, beside futures
and crypto_derivative: the account’s pool is bound to the venue’s published policy for the FX/CFD
class, which that policy must offer (risk_policy_profile_not_offered otherwise, as for any class).
An account holds one class, so its pool is still named by its currency. The issued account answers
the class in riskPolicy.profile. Orders on an FX or CFD instrument are still refused until the
canonical book trades the class.
2026-09-26: A challenge enrolls through a venue’s staged group, under the stage’s rules (preview)
POST /api/challenges/enroll issues the evaluation account on the canonical book into the venue
group the challenge maps the size to, under the stage that group runs, and the enrollment is judged
by that stage’s rules.
GET /api/challengesanswers a new field,sizes: each size a program enrolls at, with the venue group it is issued into and the stage terms it runs (target, minimum trading days, session, drawdown, return cap and duration, in money for that size). A program with sizes states its rules only there, and its percentage rules (profitTargetPct,maxTotalDdPct,ddMode,minTradingDays,allowWeekendHold) are null. An enrollment’sddModeis null when its group’s stage judges it.- The enroll route answers
409with acode, with nothing written, for a program that maps no size yet (venue_required), a size it does not map (challenge_size_unmapped), a group that runs no stage (challenge_group_unstaged) or has no route (group_has_no_route), a venue with no single policy in the program’s currency (venue_risk_policy_unresolved), and an active enrollment (enrollment_active); a currency the deployment does not issue is400currency_not_issuable. - An enrollment’s
progresson the canonical book is measured by its stage: the target and a static drawdown’s floor as levels over the starting balance, and trading days in the stage’s session. A trailing floor, a daily anchor and a high-water mark are null, as they are the risk decisions’ own state.
2026-09-26: A funding charge that can never be priced is resolved by a trdrs operator (PREVIEW)
A perpetual’s funding charge owed on an account on the canonical book, whose provider never records the rate or which has no mark on either side of its boundary within the row’s bound, is resolved by a trdrs operator, never automatically: either posted once at the rate the operator states with its source, on the charge’s recorded basis or, where none was recorded, on a basis the operator states, or ended with no charge and no journal row. Either way the account takes new exposure again once it owes nothing. Nothing else changes: a charge whose rate is recorded late still posts as it lands.2026-09-26: Personal Demo version 2026-09-26.2 takes a perpetual’s funding basis from the first mark after the hour
Personal Demo policy version2026-09-26.2 succeeds the unpublished 2026-09-26.1 and, like it, is
in force only once trdrs publishes it. Its only change is each Hyperliquid perpetual’s funding row, term
demo-crypto-funding-2026-09-26.2: with no Hyperliquid mark in force at the hour, a charge takes the
first mark received within 10 seconds after it (basis.after: "first_within_bound"), a trdrs choice
whose reason sources.basisAfter states. A mark in force before the hour always wins. A charge with
no mark on either side within the bound stays owed until a trdrs operator resolves it.
2026-09-26: A funding row may take its basis from the first mark after a boundary (PREVIEW)
A crypto derivative policy’s funding row may statebasis.after: "first_within_bound", sourced as
sources.basisAfter: where no mark is in force at a boundary, the charge takes the first mark
received after it within basis.maxAgeMs. A mark in force before the boundary always wins, and a row
without after, or with "none", takes no later mark. Each charge records its basis once, the first
time it is determinable, and never revises it; a boundary with no mark on either side within the
bound stays owed until its funding is resolved. A version that states after without
sources.basisAfter, or sources.basisAfter without after, is refused as it is today for any
unsourced or unknown field.
2026-09-26: Analytics read an account that closed a position, and say why risk coverage is incomplete
GET /api/partner/accounts/analytics, GET /api/partner/accounts/eligibility,
GET /api/partner/venues/{venueId}/accounts/{accountId}/analytics and
GET /api/partner/venues/{venueId}/risk answer for an account on the canonical book that closed a
position in its running cycle. Before, each answered 503 venue_service_unavailable (or failed on
the legacy routes) for such an account.
- A closed trade’s
entryPriceis the price its position was entered at, recovered exactly from the close’s realized profit and loss; itsquantityis the size closed, never negative. - A new field,
completeness.riskReasons, names whycompleteness.riskis false: the risk decisions’ own coverage reasons, such asinput_pendingorundecided, orrisk_coverage_started_after_cyclefor an account on the paper book. It is empty whencompleteness.riskis true. - A venue route that cannot answer names the book’s reason where it stated one
(
risk_input_busy,risk_input_halted,risk_membership_unknown,book_snapshot_mismatch,venue_revision_manifest_missing,risk_checkpoint_mismatch), still as503.
2026-09-26: The legacy issue call issues through your venue, onto the canonical book
Breaking.POST /api/partner/accounts issues only through the venue that adopted the firm, and
this entry moves the compatibility baseline.
- Each item opens its account on the canonical book, as the venue twin
POST /api/partner/venues/{venueId}/accountsdoes: the account joins the venue’s one routed group with no stage, and its pool binds to the venue’s one published risk policy in the item’s currency offering the class that currency trades, futures for USD and crypto derivatives for USDC. The request is unchanged: it names no group and no policy. - Three new per-item errors, each with nothing written:
venue_requiredfor a firm no venue has adopted,venue_group_ambiguousfor a venue with no routed group without a stage, or several, naming them in a newgroupsfield, andvenue_risk_policy_unresolvedfor a venue with no such policy, or several. A firm creates a venue as the owner of the firm its Partner key belongs to, and the venue adopts that firm. - The account trades what its venue lists and activates, of the class its pool’s policy states terms
for; its money is posted at its currency’s precision, six decimals for USDC. The balance ledger’s
provisionrow is gone: the starting balance is the account’s one opening allocation on its ledger. A reference used before this change still answers its account, from the book that holds it.
2026-09-26: The risk state shows every authority’s limits on an account on the canonical book
GET /api/risk and PUT /api/risk answer a new field, limits, on an account on the canonical book:
the version of its limits it is decided under now (inForce) and a version recorded since, which
comes into force at the next session day (next), each term with the authority that states it
(trader, firm or venue), the end-of-day close with its authority, and the session the day and
week are counted in. It is read-only: settings stay the trader’s own controls, the only terms the
trader writes, so a firm’s limit and a venue’s limit show beside them and are never theirs to
change. It is null on an account the controls alone bind. Apps should show the firm’s and the
venue’s terms read-only beside the trader’s own.
2026-09-26: An account’s instrument list states what its pool refuses (preview)
GET /api/partner/venues/{venueId}/accounts/{accountId}/instruments states, per instrument, what the
account’s pool itself refuses an entry for under the risk policy it is bound to, in the new additive
field poolRefusal: the catalogued code and parameters an entry order would be refused with, or null
where the pool can hold the instrument. A perpetual that settles in USDC on a USD account your venue
issued now reads currency_economics_unsupported here, where before it was listed with nothing in the
way and refused only when ordered; an account whose pool is not bound yet reads
collateral_policy_unverified for each instrument. Only what holds whatever the hour is stated: a
contract past its roll or a day window closing to new exposure is not listed. basis is now
account_configuration_and_policy. The trader’s own instrument list offers only what the pool can
hold.
2026-09-26: An account moved onto the canonical book keeps its daily and weekly limits
An account moved from the paper book onto the canonical book keeps the loss, profit and end-of-day limits set for it on the paper book, where they stood at the move: the day and the week count from the same starting points, and a limit it had already reached still holds it until that window ends. The limits become your firm’s terms on the account, so the trader cannot loosen them; the trader’s choice to lock their settings while a limit holds carries over as theirs. A halt your firm placed stays until your firm resumes the account. The venue’s own daily and weekly loss limits, which the paper book never enforced, apply to a moved account from the next session day on.2026-09-26: Analytics read an account on the canonical book from its ledger and risk decisions
GET /api/partner/accounts/analytics, GET /api/partner/accounts/eligibility and
GET /api/partner/venues/{venueId}/accounts/{accountId}/analytics measure an account on the canonical
book from its ledger and its risk decisions. Before, they read the paper book’s rows, which an account
the venue issued onto the canonical book does not have, and which an account moved there stopped
updating.
- Two additive fields:
pnl.imported, the result a cycle moved from the paper book carried over, andtradingDays.imported(count,lastTradedand thesessionthey were counted in), the days it had counted. Both are null for a cycle no import opened, and for every account on the paper book.netTradingincludespnl.imported. grossRealizedis realized P&L and corrections;feesare commission, fees, financing and funding; money is stated at the account currency’s own precision. A fill is dated by the instant the ledger recorded it.unrealizedandequityare the risk decisions’ own valuation, null while they have not valued the account’s current book or their inputs do not cover it;completeness.riskstates that coverage. Breaches are the decisions’ latches of the cycle and its liquidations.- The eligibility check’s
tradingDaysis null, with the reasonimported_days_other_session, for a moved cycle checked in a session other than the one its imported days were counted in. equityHistorysamples an account on the canonical book from its ledger and its risk decisions’ valuation, under its canonical cycle, with a null equity while they have not valued it.GET /api/partner/venues/{venueId}/riskmeasures it the same way, pricing its positions at the decisions’ own valuation.
2026-09-26: An order the market cannot fill now says why
On the trading routes, an order that must fill now on an account on the canonical book, refused because of its prices, answers the code that says why, neverinvalid_request:
market_data_unavailablenow carriescause, on every account:feed_down,feed_unreconciled,feed_other_contract,quote_missing,quote_one_sided,quote_invalid,mark_missing,source_mismatchorprice_time_invalid. A price that is only old staysmarket_data_stale, whoseageSecondsis never negative; a price stamped ahead of the engine’s clock isprice_time_invalid.venue_fill_refusedis new, withinstrumentandreason:outside_collarwhen the venue’s markup takes the executable price past its route’s collar,beyond_limitwhen it takes it past the order’s limit. An arriving limit order refused this way is refused whatever its time in force, and never rests, as the paper book rejects the same order.- A stop-limit whose trigger is spent, on an account a venue issued onto the canonical book, takes the market on the venue’s taking terms (the markup inside the collar, never past its limit) on a quote that crosses its limit, as on the event that spent its trigger; a print through its limit still fills it at its level. Before, a crossing quote after the trigger filled it at its level with no markup.
- An order the venue’s own session closes, reached while it waited for a price, answers
contract_not_tradingwith phasesession_closed, as the provider’s own session check does, where it answered 403permission_denied. - A quote the book was never handed answers 422
market_data_unavailable(quote_missing), where it answered 404not_found. invalid_requestnow carriesfieldandreason, the path and the code of the value refused, both null where the request’s shape as a whole is refused. An order outside the instrument’s own terms that must fill now (an order type the instrument does not list, a quantity out of its range or off its grid, a price outside its bands or off its grid) answers 400invalid_requestwith them, where it failed with a server error.
2026-09-26: A reset of an account on the canonical book runs in its own ledger
POST /api/partner/accounts/reset and POST /api/partner/venues/{venueId}/accounts/{accountId}/reset
reset an account on the canonical book in its own ledger, on the account’s lane: to the balance its
running cycle started at, with the reset recording your firm, the actor and the reason, and
account.reset queued in the same commit. Before, a reset of an account the venue issued onto the
canonical book answered 404, and one moved there from the paper book was refused. The refusals keep
their codes: not_settled also covers a command on the account’s lane whose outcome is not yet
known. New answers, for an account on the canonical book: 423 reconciliation_hold while it is held
for reconciliation, and on the partner route 503 account_unavailable (with Retry-After) when its
lane cannot take the reset now, and 503 outcome_unknown when the reset’s outcome was not learned.
A reset’s referenceId is your firm’s once across every account, on either book, as a balance
operation’s is: one your firm already used to reset any account answers duplicate and moves
nothing.
2026-09-26: A stage advance issues a paper account’s successor on the canonical book (PREVIEW)
POST /api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/advance issues a paper
account’s successor on the canonical book, as every account a venue issues is: one allocation of
startingAllocation, in the group the policy names, with its first cycle under the stage that group
runs and its pool bound to the risk policy its source’s pool is bound to. A source with no bound pool
takes the venue’s one published futures policy in its currency; with none or several, the advance
answers 409 not_eligible with successor_policy_unresolved. Before, the successor of an account on
the paper book was opened on the paper book, and an advance from an account on the canonical book
could not issue one. The successor carries the issuing firm’s provenance under the transition’s
reference, as before.
2026-09-26: Stage decisions on the canonical book count the risk decisions’ trading days (PREVIEW)
GET /api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/eligibility measures an
account on the canonical book from its ledger and its risk decisions, including an account the venue
issued there on the paper book, which was measured from the paper book’s rows it does not have.
facts.tradingDaysis the count the account’s risk decisions keep: the session days, in the stage’s session, on which the cycle’s positions changed, starting from the days the paper book counted for a cycle that moved to the canonical book. It is null until the decisions take the cycle under its stage. Before, it counted the ledger’s fills by when each traded.facts.accountRevisionandfacts.decidedRevisionare new: the head revision the facts were measured at, and the account revision the risk decisions had decided through. Both are null for an account with no canonical book.facts.netTradingPnlincludes funding charges and, for a cycle that moved to the canonical book, what it traded on the paper book before it moved.facts.breachesnames every latch the decisions made in the cycle by its rule (max_drawdown,daily_drawdown,daily_loss,weekly_loss,daily_profit,weekly_profit,eod_close,maximum_return,duration_expired) besidestop_out, andfacts.observedRulesnames the stage’s own drawdown, cap and duration rules once the decisions take the cycle under it, and the rules of the limits in force at their last decision.
POST /api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/advance on an account on the
canonical book answers 409 stage_decision_pending while its risk decisions have not decided through
its head. It clears without any action: retry it. An account whose pool is bound to no risk policy
has no decisions to wait for, so its trading days stay unknown and the advance answers not_eligible
with incomplete_history. Facts measured at a head that has since moved answer 409
version_conflict.
2026-09-26: Account lists read an account on the canonical book from its ledger
GET /api/partner/accounts and GET /api/partner/venues/{venueId}/accounts state an account on the
canonical book from its ledger: its balance, the balance its running cycle started at, and when it was
last reset. Before, the partner list read the paper book’s row, which an account the venue issued onto
the canonical book does not have (it answered a zero balance), and the venue list stated no starting
balance for it. An account that moved onto the canonical book is no longer stated as it stood when it
moved.
Each row of GET /api/account/orders documents filledQty, which it has always carried: how much of
the order filled, or null where the venue reports no such number.
2026-09-26: A crypto perpetual on a canonical USDC account pays and receives funding (PREVIEW)
A crypto perpetual on an account the canonical book holds now takes exposure where the account’s risk policy states a funding row for it. At each boundary of the row’s schedule, each position pays or receives its funding once: its quantity, times the contract’s value per price unit, times the mark at the boundary, times the provider’s settled funding rate for that boundary, a long paying a positive rate and a short receiving it, posted in USDC’s six decimals. Until the provider’s settled rate is recorded, within the row’s publication grace the boundary waits, and past it the charge is owed: an order that adds exposure is refusedcollateral_unvalued with params.cause
obligation_pending until the rate is recorded and the charge posted. An owed charge is never posted
as zero or at an estimate. An order on a perpetual whose policy states no funding row for it is
refused collateral_policy_unverified with params.cause missing. Before, every order on a
perpetual that added exposure was refused product_economics_unsupported.
2026-09-26: An account on the canonical book sends its risk and balance events
A firm’s account on the canonical book now sendsrisk.locked and risk.unlocked for every lock
and unlock, and balance.recorded for every balance operation it applies, as an account on the paper
book always has. The payloads are unchanged; balance.recorded states the amount the operation
posted. Before, an account the venue issued onto the canonical book sent neither lock event and no
balance event.
2026-09-26: Brackets and stop-limit orders on a canonical account
An account the canonical book holds now declaresnativeBracket and stopLimit in its
capabilities, and no bracketEntryTypes, so POST /api/trading/order takes a stop-loss and
take-profit bracket on any entry type and a stop_limit order there, where both answered 400. The
request shapes are unchanged.
- A bracket’s exits rest the moment its entry fills, in the same commit: a reduce-only stop and a reduce-only target that cancel each other, each sized to what that fill opened. An entry that rests refuses an exit on the wrong side of its price, a limit’s level, a stop’s trigger or a stop-limit’s limit; an entry that fills now rests its exits as stated. A tick distance is measured from the price the entry fills at, or for an entry that rests, from its price. The account’s protection lane shows the bracket from the moment the order is accepted.
- When a fill closes a position, flat or past flat, every other reduce-only order on that instrument
ends with
endReasonposition_closed, so an exit placed for one position never fills against the next. - A stop-limit rests with its trigger and its limit. Once a price crosses its trigger it rests as a
limit, and its order row reads
orderType: limitwith no trigger; replacing it as a stop-limit then answers409. On the price that crosses its trigger it fills only where the market is already through its limit, at the venue’s price for an order that arrives then, never past its limit. - An order that could add exposure and whose venue commission is in another currency than the
account’s is now refused as it is placed,
currency_economics_unsupported(422), where a resting one was accepted and never filled.
2026-09-26: An order row states why the order ended
Each row ofGET /api/account/orders gains endReason: trader_cancelled, oco_sibling_filled,
replaced, liquidation_cancelled, position_closed, import_entry_cancelled or import_replaced.
It is null on an order still working, filled or rejected, and on every order a venue ends without
stating why, which is every external broker’s today. An account that moved onto the canonical book
lists the working orders the move ended beside its own, each cancelled with import_entry_cancelled
(an order that could add exposure) or import_replaced (a protective order the same order on the
canonical book replaced). The list of reasons grows: show an unknown value as it is.
2026-09-26: A balance operation’s reference reads back from either book, and stays the firm’s once
GET /api/partner/balance-op?referenceId=, and its venue twin, now answer an operation on an account
the canonical book holds, where they answered 404: the account, the operation as the firm sent it
(credit, debit or adjustment), the amount at the currency’s posting precision, applied and
the instant it applied. A reference the firm used on an account before that account moved onto the
canonical book answers as it did before the move, legacy_unknown included. The shape is unchanged.
A firm’s referenceId is the firm’s once across all its accounts, as it always has been, now on the
canonical book too: reused on any other account, or twice at once on two accounts, it applies once
and every other attempt answers 409 with duplicate: true.
2026-09-26: A canonical book write’s refusal names its own code
An order the canonical book refuses in its own transaction now answers a code of its own, each with no parameters, where it answeredorder_rejected with only a sentence to tell them apart:
not_found (404), permission_denied (403), invalid_request (400), version_conflict (409),
idempotency_conflict (409), position_mode_unsupported, product_economics_unsupported and
currency_economics_unsupported (422). The status and the error sentence are unchanged. A
refusal the catalogue does not name stays order_rejected, its sentence naming the reason. An
order on a perpetual in a canonical account, which the book does not value yet, answers
product_economics_unsupported.
2026-09-26: A canonical account’s orders meet the venue’s terms on the canonical book alone
An order on an account the canonical book holds is admitted by the canonical book alone. The paper book’s venue admission, which looked a listing up under the instrument’s root and valued a market order on the paper tape, no longer reads it: an order on a dated contract the venue lists (CME:NQZ2026) is no longer refused instrument_not_permitted, and a market order is no longer
refused valuation_required where the paper tape had no price. Each gets the canonical book’s own
answer, such as contract_not_trading outside the contract’s session.
On such an account, an order that adds exposure, whether it fills now or rests, meets the venue’s
terms in its own transaction and is refused with the venue admission codes:
venue_conditions_missing, venue_route_missing, venue_route_retired,
venue_instrument_disabled, venue_instrument_expired, entry_halted, instrument_not_permitted,
below_min_notional and reduce_only_violation, with params.instrument the venue’s instrument
id. An order that fills now answered these as order_rejected, or as a 500, before.
A reduction passes every one of them. It fills at the executable side of a fresh quote, on the terms
the venue states, or with no markup, collar or commission where the venue states no conditions or no
route; an order that fills now was refused there before. The account’s action verdicts state the
same refusals for open, and none of them for protect, reduce or flatten.
2026-09-26: A risk-terms refusal can name a perpetual’s funding term
Theterm parameter of risk_terms_missing, risk_terms_stale and risk_terms_contradictory
gains funding: a perpetual’s funding row, which states the venue whose settled funding rate it is
charged, its boundaries, its sign and the price its notional is taken at. A perpetual takes new
exposure only while its account’s risk policy states a funding row for it, in force and charged from
the venue that prices it; a position already held is still valued without one. Nothing raises it
yet: the canonical book still refuses perpetuals on every order path. A client that translates term
keeps a generic wording for a value it does not know, as the catalogue already requires.
2026-09-26: A venue’s USDC account posts its money in six decimals (PREVIEW)
POST /api/partner/venues/{venueId}/accounts, and its operator twin, now open a USDC account on the
canonical book where the deployment issues USDC (a sandbox): its pool is bound to a venue policy in
USDC that offers crypto_derivative, and its money is posted, held and stated in USDC’s six decimals,
so the answer’s balance has six places ("50000.000000"). A USD account keeps cents. A balance
operation on a canonical USDC account takes up to six decimals, and a finer amount is
400 amount_precision_exceeded with params.decimals 6; a USDC account the canonical book does not
hold keeps two.
A crypto perpetual pays funding the canonical book does not record yet, so no instrument adds
exposure in a USDC pool yet: its orders that add exposure are refused, as before.
POST /api/partner/venues/{venueId}/risk-policies, and its operator twin, refuse a version whose
posting term states a currency at another precision than the canonical book posts it at (USD in two
decimals, USDC and USDT in six) as 409 risk_policy_posting_mismatch, storing nothing.
2026-09-26: A balance operation on an account held for reconciliation answers 423
POST /api/partner/balance-op and the venue balance route,
POST /api/partner/venues/{venueId}/accounts/{accountId}/balance and its operator twin, answer a
credit, debit or adjustment on an account the canonical book holds, while that account is held for
reconciliation, with 423 and the code reconciliation_hold, recording nothing. The legacy route
answers { "error": ..., "code": "reconciliation_hold", "params": {}, "referenceId": ... } and the
venue route { "error": "reconciliation_hold" }. The same reference can be sent again once a trdrs
operator releases the hold.
2026-09-26: The Partner API refuses a withdrawal it cannot cover
POST /api/partner/balance-op, on an account the canonical book holds, answers a debit it
cannot make with a new 409: { "code": "balance_refused", "reason": ... }, where reason is
insufficient_funds (the pool’s free collateral is less than the amount), permission_denied (a
hold stands on the account) or invalid_request (a held position cannot be valued now). Nothing is
recorded, and the same referenceId may be sent again once the cause clears.
2026-09-26: A venue issues accounts on the canonical book, in USD or USDC, bound to its risk policy (PREVIEW)
POST /api/partner/venues/{venueId}/accounts, and its operator twin, in the venue account routes, a
PREVIEW group, now open the account on the canonical book. The body adds two required fields:
currency, the pool the account is held in (USD everywhere, USDC in a sandbox; any other is
400 currency_not_issuable with params.currency and params.environment), and riskPolicy,
{ policyId, profile }, one of the venue’s published risk policies and the product class the pool
holds, futures or crypto_derivative. The account opens with its starting balance, in its group
under the stage version the group runs, with its pool bound to that policy’s version in force and the
venue’s daily and weekly loss limits in force recorded on it. A policy that is not published, is in
another currency, does not offer the class or belongs to another venue is refused with
409 risk_policy_unpublished, risk_policy_currency_mismatch, risk_policy_profile_not_offered or
risk_policy_authority_mismatch, before anything is written. The answer adds book: "canonical" and
riskPolicy with its version and sequence; balance is the ledger’s. The same
referenceId with the same body answers the same account with created: false and 200; with any
other body it is 409 idempotency_conflict. A balance operation on such an account moves its ledger:
a credit or an adjustment posts, and a debit is a withdrawal of free collateral, refused with
409 balance_refused and a reason when the pool cannot spare it or a hold stands.
2026-09-26: An account held for reconciliation refuses new exposure
trdrs recomputes every committed change to an account on the paper book independently. When the book does not follow from what happened to it, or one effect was counted twice, the account is held for reconciliation until a trdrs operator investigates and releases it. While it is held, the order, reverse and replace routes answer an order that may add exposure with423 and the new code
reconciliation_hold, which carries no parameters; a reduce-only order, a close, a flatten and a
cancel stay available, and the account takes no credit, debit or reset. The book is never
rewritten by the hold. GET /api/trading/actions states the same refusal in its open verdict.
2026-09-26: A venue stores and publishes its own risk policy (PREVIEW)
/api/partner/venues/{venueId}/risk-policies, /api/partner/venues/{venueId}/risk-policies/{policyId}
and /api/partner/venues/{venueId}/risk-policies/{policyId}/publications, and the same routes under
/api/operator/venues/{venueId}/risk-policies, /api/operator/venues/{venueId}/risk-policies/{policyId}
and /api/operator/venues/{venueId}/risk-policies/{policyId}/publications, a PREVIEW group, store,
publish, list and read the account risk policies a venue states for its own accounts: the margin,
stop-out, recovery, valuation, settlement and posting terms its issued accounts are held to.
POST .../risk-policies with { policy } stores one immutable version (201, or 200 with
created: false for the same content again); GET .../risk-policies/{policyId} reads one policy
with each version’s content; POST .../risk-policies/{policyId}/publications with { version }
puts it in force, recording it on every account pool bound to the policy in the same
transaction, with the Idempotency-Key as the publication’s reference. Both need venue:configure;
the reads need venue:read. A policy has one owner: a version under another venue’s or trdrs’s
policy id is 409 risk_policy_owner_conflict, a policy id beginning trdrs- is
409 risk_policy_id_reserved, other content under a stored version is
409 risk_policy_version_conflict, a version with an unsourced figure is
409 risk_policy_unsourced, and the version already in force is 409 risk_policy_unchanged.
2026-09-26: An entitled instrument names a source trdrs serves per trader (PREVIEW)
An instrument candidate that names anentitlement, in the venue instrument routes, a PREVIEW group,
is priced from each trader’s own feed, so its pricing.sourceId must be a source trdrs serves per
trader, rithmic today. Any other is refused with 400 entitled_source_unserved, field
instrument.pricing.sourceId, when the candidate is saved, and again when a candidate saved earlier
is activated. Before, such an instrument activated and its orders that add exposure were refused one
by one; no account could ever be valued on it.
2026-09-26: The server time carries milliseconds
GET /api/market/time answers timeMs, the engine clock in epoch milliseconds, beside time,
which is unchanged. Both come from one reading. A client that times the request knows the engine
read timeMs within the round trip, so it can bound its clock offset from the engine to half the
round trip, where the whole second in time leaves up to a second.
2026-09-26: A risk-terms refusal can name the terms of an FX or CFD pool
Theterm parameter of risk_terms_missing, risk_terms_stale and risk_terms_contradictory
gains four values for the terms an FX or CFD instrument is bound by: cfd_margin (its margin row),
markup (how far its source quote is widened into the executable quote), financing (its rates and
the rollover rule they are charged on) and conversion (the route a currency other than the
account’s is converted along). Nothing raises them yet: no account’s pool is bound to FX or CFD
terms, and FX and CFD instruments stay refused on every order path. A client that translates term
keeps a generic wording for a value it does not know, as the catalogue already requires.
2026-09-26: Venue loss limits are enforced where the venue’s accounts are decided (PREVIEW)
dailyLossLimit and weeklyLossLimit in VenueRiskPolicy, in the venue conditions routes, a
PREVIEW group, are now taken while every account the venue issued is bound to its published risk
policy version. The write that saves a limit records it on every account it applies to, which counts
it from its next session day; a breach holds the account, and an order that adds exposure is refused,
until that session day ends. Where some account is not bound, such as one held at a provider, a
limit is still refused with 400 loss_limit_unenforced, and the effective conditions report each
limit’s enforced as whether it is.
2026-09-26: A stage states a consistency cap and a duration (PREVIEW)
VenueStagePolicy, in the venue stage routes, a PREVIEW group, gains two optional terms, each
null when a policy does not state it, which is how every policy stored before reads.
maximumReturn is a return on equity, in money above the cycle’s starting balance, at or above
which the cycle fails. maximumDays is the whole days a cycle may run from its first trade before
it fails. A breach of either flattens the account and locks it with reason eval_breach until the
account’s reset. Both are economic, as the drawdown rule is: activating a policy that adds or moves
one waits for the accounts to be flat.
2026-09-25: A venue’s margin comes from its risk policy, not its conditions (PREVIEW)
margin in a venue condition profile and group override, in the venue conditions routes, a
PREVIEW group, was saved and applied to no trading: what an account must hold comes from the
venue’s published risk policy version, the one authority. A profile, group override or preview that
states a margin policy is now refused with 400 margin_policy_superseded, field naming it; the
field takes null. A profile or override stored before the refusal still reads with its value, and
the effective conditions report it as applied: false.
2026-09-25: Venue loss limits are refused until they are enforced (PREVIEW)
dailyLossLimit and weeklyLossLimit in VenueRiskPolicy, in the venue conditions routes, a
PREVIEW group, were saved and never applied to trading. A limit that is stored and not enforced
reads as a protection the account does not have, so a profile, group override, preview or account
override that states one is now refused with 400 loss_limit_unenforced, field naming the limit.
Both fields stay in the shape and take null. A profile or override stored before the refusal still
reads with its value, and the effective conditions report each of the two as enforced: false.
2026-09-25: The margin_stop_out lock reason
lockReasonon the risk lock, andreasonon arisk.lockedwebhook, can bemargin_stop_out: a margin stop-out the account’s risk decisions recorded on the event-driven risk path of the paper book. It holds until the account is shown recovered on current prices; the manual unlock does not lift it. Where a drawdown breach holds the same account, the lock names the drawdown. No account a partner trades is on that path yet.
2026-09-25: Two more risk holds
- A
423 risk_locked, and the order lane’s409, can name two more holds inparams.holds:stop_out_latch, a stop-out the account’s risk decisions recorded, which stays until the account is shown recovered on current prices; andrisk_uncovered, risk decisions that do not cover the account’s current state, because a price it depends on is stale, interrupted or cannot be shown complete, or because the decisions have not kept up with its changes. Each refuses new or increased exposure; cancels, exits and reductions stay available. They hold only accounts on the event-driven risk path of the paper book, which no account a partner trades is on yet.
2026-09-25: The saved stop-out ratio is retired (PREVIEW)
stopOutEquityRatio is removed from VenueRiskPolicy in the venue conditions routes, a PREVIEW
group. It was saved and never applied to trading; a stop-out is now a threshold of a versioned
account risk policy. A profile, group override or account override that still names it is refused as
invalid_request, and it is gone from every stored profile and override, whose other values are
unchanged. Effective conditions no longer report it.
2026-09-25: Contract and risk policy refusal codes join the catalogue
TheRefusal catalogue adds eight codes the paper book will answer with once it binds every order
to a versioned contract and every account to a versioned risk policy. No route answers with them
yet; a client that translates refusals can add them now, and keeps its generic message for a code
it does not know.
continuous_symbol_not_contract(instrument,root): a continuous chart symbol names a product, not the dated contract an order trades.contract_unregistered(instrument): no registered contract version has that name.contract_not_trading(instrument,phase,lastTradeAt): the contract isnot_listed,close_onlybefore its last trade, orexpired.margin_window_closing(instrument,overnightAt,overnightInitial,overnightMaintenance,asset): new futures exposure closes before the day margin window ends, and the params state the overnight requirement per contract a held position meets fromovernightAt.risk_policy_unbound(instrument): the account’s collateral pool is bound to no published risk policy.risk_terms_missing,risk_terms_contradictory(instrument,term) andrisk_terms_stale(the same andeffectiveUntil): a term the policy must state for the contract is absent, out of its effective interval or in conflict with the contract or the account.
2026-09-25: A bare futures root names one safe dated contract, or is refused
A Rithmic order on a bare root (ZN, ES) now goes to the dated contract the product’s own
exchange rule names, not one calendar shared by every product. Equity index roots keep the third
Friday rule; Euro FX follows its last trade two business days before the third Wednesday; the
Treasury roots follow first intention day, two business days before the delivery month, so a bare
Treasury root never names a contract in its delivery period. Business days come from the served
CME calendar, and a date it does not cover is never assumed.
- Three trading refusal codes join the catalogue.
bare_root_unresolvedrefuses a bare root that names no one safe contract: itscauseisdates_unmodeled,dates_uncovered,unsafe_windoworambiguous(the account holds the root in another contract), with the rule’scontract, thewindowandboundaryit is inside, the specificationsourceand the connection’s deliverycutoffTerm.contract_past_safe_windowrefuses an order adding exposure to a dated contract inside its unsafe window, andGET /api/trading/actionsstates it for a position held there.contract_dates_uncoveredrefuses such an order when the calendar cannot place the window. - A dated contract (
ZNZ6) is always sent as itself. A close, a flatten, a protective exit, a cancel or an amend keeps the position’s or the order’s own contract after the rule rolls. - On the paper book the held-lane window after a roll now ends a day after the rolled-away
contract’s own last trade, and
futures_contract_unknowngivesno_roll_rulewhen the calendar cannot date the contract.
2026-09-25: A staged account that cannot prove its stage version is close-only, and an issued account’s reset is audited
Breaking. A reset of an issued account now requires a reason and a settled book, and this entry moves the compatibility baseline. No client or integrator used the route, so there is no compatibility path.- A new refusal code,
stage_version_unrecorded, withparams.reason(no_record, oractivated_after_openingwhen the rules in force came into force after the running cycle opened and it has traded) andparams.stageId. It answers423on an order that would open or add exposure on an account whose group runs a stage and whose running cycle cannot prove the stage version it is judged by. Cancels, exits and reductions stay available, andGET /api/trading/actionsstates the same:openrefused, on the instrument and across the account, andprotect,reduce,flattenandcancelallowed where the position allows them. Normal trading returns when the version is established or the issuer resets the account. POST /api/partner/accounts/resetrequirescomment, the reason for the reset, recorded with it on the balance ledger with the firm as actor and the instant; without it the answer is400withcode: reason_required. The venue twin,POST /api/partner/venues/{venueId}/accounts/{accountId}/reset, requirescommentas well (Preview) and records the acting member or key.- A reset of an issued account is refused with
409and acode, moving and recording nothing, while the account holds a position, a working order or a command whose outcome is unknown (not_settled), has an unresolved liquidation incident or a drawdown breach it has not been flattened from (risk_unresolved), or has a negative balance (deficit_unreconciled). A reset never closes a position or cancels a working order: close them first. A breach the ended cycle recorded stays on record under that cycle. - An account a firm or venue issued is reset only by its issuer: the trader’s own Demo reset,
POST /api/brokers/paper/reset, answers403withcode: issued_accountfor it.
2026-09-25: Balance amounts name their currency
Every Legacy Partner API and venue answer that states an account’s money now names the currency it is in, so a USDC amount is never read as a USD one.- The
balance.recordedevent’sdataaddscurrency, the account’s currency thatamountis in. POST /api/partner/balance-opand its venue twin answer withcurrency; the receipts,GET /api/partner/balance-opandGET /api/partner/venues/{venueId}/balance-ops/{referenceId}, carry thecurrencythe ledger row records.- The five risk controls, on
GETandPUT /api/partner/accounts/riskand the venuerisk-controlsroutes, addcurrency, which the loss and profit values are in. - A venue’s issue answer adds
currency, and the venue stage eligibility schema now documents thecurrencyits facts already carried. GET /api/partner/usageand its venue twin addcurrency: "USD": trdrs bills in USD, andamountCentsandpriceCentsPerActiveAccountare cents of it, whatever currency the firm’s paper accounts are held in.- A balance operation whose
amounthas more decimals than the account’s currency states money at, two for USD and two for USDC on the paper book, is refused as400with the new codeamount_precision_exceededandparamsnaming thecurrencyand itsdecimals, before anything is recorded; the same reference can be sent again with the amount corrected. This code andcurrency_not_issuableare partner and admin errors in the{ error, code, params }shape, listed on Errors, not trading refusals.
2026-09-25: Refusals carry a code and parameters, and an account says what it may do
Every refused trading request now carries a stablecode and its params beside error, which
stays the English fallback. The codes are one catalogue, the Refusal model of the API reference:
the account-mode codes of a Binance, Bybit or Hyperliquid account, the paper book’s codes of the
entries below (product_unproven names the instrument, the account currency and the products
proven for it), unknown_instrument and
asset_class_not_supported from the asset-class routing, an issued account’s venue conditions
(entry_halted, instrument_not_permitted, order_quantity_above_limit and the rest),
risk_locked with the account’s holds in params.holds, feature_disabled, the engine’s own
admission codes, and order_rejected for any other rejection. params never carries a secret, an
account number or text a provider sent. Errors lists what each
code carries.
GET /api/trading/actionsreturns whether the account may open or add exposure (open), reduce a held position through the order route (reduce), close part of it through the close route (close), protect it (protect), flatten it (flatten) and cancel (cancel), on one instrument or across the account, with the refusal each refused action would get. Each verdict runs its own route’s standing checks: under a holdreduceis refused as the order route refuses it, andcloseis refused unless the provider enforces it as reduce-only. It is advisory: the order is judged again when it is sent. Requires a Trading API key.- Each
accountMode.refusalsentry on the account snapshot addsparams. - A
423 risk_lockedaddsparams.holds:trading_lock,drawdown_latch,liquidation_incident, or null when the holds could not be read. - A
403 feature_disablednames the switched-off feature inparams.feature. - On an issued paper-book account, a resting order or bracket whose venue terms are missing or
disagree with the paper book is refused when it is placed (
venue_terms_missing,venue_terms_mismatch), as an immediate order already was, instead of resting until the matcher rejected it.
2026-09-25: A cycle is judged by the rules it opened under
Stage eligibility, advancement and the drawdown rule judge an account’s running cycle by the stage version it recorded when it opened: its profit target, trading days and the session they are counted in, disqualifying rules and drawdown. A paper-book account records the version in force when it is placed or moved into a group that runs the stage, when it resets and when an advance issues it. Activating a version with new rules takes effect at once, even while accounts running the stage hold positions, and reaches each account at its next cycle. Where a passing account lands,nextGroupId, is routing: it comes from the version in force at the advance, so a change of
destination alone applies at once. Preview groups only.
- The eligibility response adds
economicHash,routingPolicyIdandroutingActivationRevision.policyId,activationRevisionandeconomicHashname the version that judges the cycle; the routing fields name the version in force now. An advance records both and is refused withversion_conflictif either has moved since it was decided. - Activating a stage version no longer waits for the stage’s accounts to be flat, and no longer
answers
409 not_quiescent. - For an account on the venue ledger, eligibility counts only the running cycle: its trading P&L,
trading days and recorded stop-outs start at its opening allocation, and its
cycleIdnames that allocation, so a reset account is judged on what it did since the reset. - A cycle with no record of the rules it opened under answers
409not_eligiblewithstage_version_unrecorded, both for the eligibility read and for an advance, rather than being judged by the version now in force, and the drawdown rule does not watch it. That is a paper-book account moved into the stage part-way through a traded cycle after the rules now in force came into force, until it resets, and every account held at a provider, whose eligibility read previously listed the missing evidence.
2026-09-25: Issue a paper-book account in USDC
Create evaluation accounts acceptscurrency on each item, USD or USDC, and USD when it is omitted, which is what
every account issued before the field existed is held in. The currency is fixed when the account
opens; no existing account changes currency.
- USDC accounts are issued in the sandbox only, for the sandbox partner flow. Any other
deployment refuses a batch naming USDC as
400with the new codecurrency_not_issuableandparamsnaming thecurrencyand theenvironment, and creates nothing. - A USDC account’s money is stated in two decimals, a disclosed paper-book rule and not USDC’s native six-decimal precision. Each fill’s profit and loss is rounded to the hundredth, so rounding can accumulate across fills.
startingBalancestays a whole number of that currency, 1000 to 10000000, as on the venue route. An account may later hold cents from trading.- Each result carries
currency: the item’s on a fresh create, the account’s own on a re-answeredreferenceId. - A USDC account trades
HYPERLIQUID:BTC, a Hyperliquid core perpetual that settles in USDC, the one product proven on a USDC account so far. Its fills, profit and loss, balance, balance operations, stage checks and resets are in USDC. Every other instrument is refused with the new codeproduct_unproven, and its account instruments list onlyHYPERLIQUID:BTC. - A USD account still refuses every registered perpetual as
settlement_asset_unmodeled. Its account instruments no longer list any perpetual, since none of them settles in USD. - Stage eligibility adds
currency, the account currency itsnetTradingPnlandprofitTargetare stated in, as firm analytics already did. - The venue route
POST /api/partner/venues/{venueId}/accountsissues USD accounts only: a body namingcurrencyis refused as400 invalid_request, and a USDC account is never placed into a venue group.
2026-09-25: The paper book refuses what it cannot price honestly
The paper book, under a trader’s own Demo and every account a venue issues, now refuses orders and reports values as unknown where the contract, the multiplier, the price or the settlement asset is not reliable. Each refusal is a400 or 422 with its code, sends and books nothing, and
releases the idempotency claim.
futures_exposure_refused: a futures position on the paper book is keyed by its root, not by a dated contract, so every futures order that would open or add exposure is refused, resting and bracket orders included. An existing position can still be closed, and protected with exits, while the contract it was opened on is the one priced. After the engine’s roll it is refused withfutures_contract_unknownand itsunrealizedPnlisnull; it is never priced from the next contract. So is a position opened in the nine days after a roll, while the rolled-away contract could still have priced it.instrument_not_tradable: CL, MCL, NG, GC, MGC and SI. They leave the paper book’s account instruments.unknown_instrument: a symbol with no contract specification on the paper book, including one only the chart feed serves. Charting it is unchanged.market_data_stale,market_data_unavailable,market_data_delayed: a trade or mark older than 10 seconds by its own time, no price, or a delayed feed outside the sandbox. A sandbox Rithmic Test login still prices practice trades at its true, delayed, age; symbol metadata labels itdataStatus: delayed_streaming.settlement_asset_unmodeled: a registered perpetual on an issued account not held in the asset it settles in, and futures on an account not held in USD. The paper book’s registered perpetuals are the Hyperliquid core perpetuals, which settle in USDC, and the Binance and Bybit USDT-quoted perpetuals, which settle in USDT; a builder-deployed Hyperliquid market is not registered and is refused asunknown_instrument. A Personal Demo settles a registered perpetual’s profit and loss as synthetic USD at a fixed 1:1 parity and holds no stablecoin.venue_terms_mismatchandvenue_terms_missing: an issued account’s venue instrument whose multiplier, tick, quantity unit, product model, settlement currency or commission currency disagrees with the paper book, or an entry with no venue terms. A dated listing no longer admits an order the paper book keys on its root.
openedAt, the time the account’s own fills say the position opened
(null when that cannot be established).
2026-09-24: Risk events carry an event id and a revision
risk.locked and risk.unlocked deliveries add two fields to data: eventId, which is the same
on every delivery and retry of one lock change, and revision, which increases with each lock
change on the account. Each event is recorded in the transaction that changes the lock, so a
restart cannot drop one. Existing fields are unchanged. Receive events
explains deduplication and ordering.
2026-09-23: Venue risk book (preview)
GET /api/partner/venues/{venueId}/riskandGET /api/operator/venues/{venueId}/riskread every paper-book customer account the venue issued, up to 500, as one book at one instant (asOf): totals, exposure by instrument with long, short, net and gross quantity and notional, every open position and working order, and each account’s figures. Requiresaccount:read.- A total is stated only when every included account answered in one currency; a total a missing
mark would change is
null. Notional uses a mark no older than 10 seconds. - The
hedgingsection lists the hedge engine’s current targets, policies, open incidents and execution metrics beside customer exposure, never netted into it. Withouthedge:readit readsstate: unavailableand the rest of the book is still returned. historyaggregates the per-account equity samples per minute bucket overhistoryWindowandhistoryInterval. A point carries a total only when every account in scope was sampled in that bucket; otherwise it says why.
2026-09-22: Venue team membership
An owner can now manage who works on an organization’s venues from a signed-in session. Each person keeps their own trdrs sign-in; no password or Venue key is shared.GET /api/operator/organizations/{organizationId}/membersreturns each member’semail.POST /api/operator/organizations/{organizationId}/membersacceptsemailas an alternative toauthUserId. An address without a verified account creates a pending invitation and receives email. It grants no access until that exact address completes verified sign-in, when the role activates automatically.- Pending invitations are returned with
pending: trueand may be changed or cancelled by email. POSTandDELETEon the same path are in the reference, with their version, last-owner and idempotency behavior.
2026-09-21: Hosted Connect Link and venue hedging preview
Venues can now open the same short-lived Connect flow from the trdrs app, an installed back office, or their own website. Exact website origins are registered before a backend may mint a session. The venue hedging preview keeps customer execution separate from the venue-owned hedge account and routes every hedge command through the existing per-account execution coordinator.- Connect setup and backend sessions:
/api/operator/venues/{venueId}/connect/origins,/api/partner/venues/{venueId}/connect/sessions, and/api/partner/venues/{venueId}/connect/sessions/{sessionId}. - Browser handoff:
/api/connect-link/mount,/api/connect-link/sessions/{sessionId}/claim,/api/connect-link/sessions/{sessionId}/complete, and/api/connect-link/sessions/{sessionId}. - Partner hedge controls:
/api/partner/venues/{venueId}/hedges,/api/partner/venues/{venueId}/hedges/policies,/api/partner/venues/{venueId}/hedges/activation,/api/partner/venues/{venueId}/hedges/calculate,/api/partner/venues/{venueId}/hedges/intents/{intentId}/dispatch,/api/partner/venues/{venueId}/hedges/intents/{intentId}/reconcile,/api/partner/venues/{venueId}/hedges/emergency-stop, and/api/partner/venues/{venueId}/hedges/flatten. - The signed-in operator twins use
/api/operator/venues/{venueId}/hedges,/api/operator/venues/{venueId}/hedges/policies,/api/operator/venues/{venueId}/hedges/activation,/api/operator/venues/{venueId}/hedges/calculate,/api/operator/venues/{venueId}/hedges/intents/{intentId}/dispatch,/api/operator/venues/{venueId}/hedges/intents/{intentId}/reconcile,/api/operator/venues/{venueId}/hedges/emergency-stop, and/api/operator/venues/{venueId}/hedges/flatten.
2026-09-21: Venue branding and instrument reference data
An installed back office can now manage its venue’s ongoing brand and populate instrument forms with one scoped Venue key. The operator-session twins use the same handlers and checks. These routes do not change listing approval, company roles, referral links, accounts or live trading.GET/PUT /api/partner/venues/{venueId}/brandandGET/PUT /api/operator/venues/{venueId}/brandread and update the venue’s name and description (venue:read,venue:configure). Writes include theupdatedAtvalue from the preceding read; a stale write returnsversion_conflictinstead of overwriting a later change.POST /api/partner/venues/{venueId}/brand/logoandPOST /api/operator/venues/{venueId}/brand/logovalidate, sanitize and store an engine-hosted PNG (venue:configure) with the same optimistic timestamp check.GET /api/partner/venues/{venueId}/reference/instrumentsandGET /api/operator/venues/{venueId}/reference/instrumentsreturn the static contract reference catalog (venue:read). The read grants no market-data entitlement and activates no venue instrument.
2026-09-19: Stages and analytics on accounts held at a provider
Stage eligibility and the account analytics now answer for an account a venue holds at a provider, from the provider’s own records of its fills, instead ofpermission_denied. Nothing
is written and no second set of books is kept. Preview groups only.
GET /api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/eligibilitymeasures a provider-held account from the provider’s records.observedRulesis empty for such an account, so a policy naming a disqualifying rule answersunobserved_disqualifying_rule.GET /api/partner/venues/{venueId}/accounts/{accountId}/analyticsand the/api/operator/…twin answer for a provider-held account withbook: provider, no equity history and no rules.- The venue read carries
level2.appliesAtProviderbesideapplies: for an account held at a provider onlystagesis applied; its orders and fills are the provider’s own. - The advance on a provider-held account still answers
permission_denied: the successor would have to be created at the provider.
2026-09-19: One key for a venue backend
The four things a venue’s backend still needed the Legacy Partner key for now exist on the venue routes: the five per-account risk controls, usage, the receipt of one balance operation, and webhooks. Each runs the same operation the legacy route runs, behind a venue scope, under both families. A webhook registered through either is the same row and fires for the same events. The legacy routes are unchanged and stay until every firm portal has moved. Preview groups only; nothing on the market, trading or Partner routes changed.GET/POST /api/partner/venues/{venueId}/accounts/{accountId}/risk-controlsandGET/POST /api/operator/venues/{venueId}/accounts/{accountId}/risk-controls: read and replace the five per-account controls (account:read,risk:halt).GET /api/partner/venues/{venueId}/usageandGET /api/operator/venues/{venueId}/usage: the venue’s metered usage for a month (venue:read).GET /api/partner/venues/{venueId}/usage/accountsandGET /api/operator/venues/{venueId}/usage/accounts: the accounts behind that number (venue:read).GET /api/partner/venues/{venueId}/balance-ops/{referenceId}andGET /api/operator/venues/{venueId}/balance-ops/{referenceId}: the durable result of one balance operation by the Idempotency-Key of its write (account:read).GET/POST /api/partner/venues/{venueId}/webhooksandGET/POST /api/operator/venues/{venueId}/webhooks: list and register webhooks (venue:read,venue:configure).DELETE /api/partner/venues/{venueId}/webhooks/{webhookId}andDELETE /api/operator/venues/{venueId}/webhooks/{webhookId}: remove one (venue:configure).POST /api/partner/venues/{venueId}/webhooks/{webhookId}/testandPOST /api/operator/venues/{venueId}/webhooks/{webhookId}/test: send a signed test ping (venue:configure).GET /api/partner/venues/{venueId}/webhooks/{webhookId}/deliveriesandGET /api/operator/venues/{venueId}/webhooks/{webhookId}/deliveries: the delivery log (venue:read).
2026-09-18: Level 2 on the paper book, one record per company, two switches
The venue’s rules now govern the accounts it issues on the paper book: an order is asked the venue’s conditions before it is claimed, a fill takes the venue’s markup inside the route’s collar and the venue’s commission, a stage check reads the account’s own fills, and a drawdown rule on the stage policy flattens and locks on a breach. Connect and every venue’s Providers list are drawn from one record per company. Preview groups only; nothing on the market, trading or Partner routes changed.- The venue read carries
level2: { enabled, applies }andcompany. POST /api/partner/venues/{venueId}/level2andPOST /api/operator/venues/{venueId}/level2turn level 2 on or off. Creating the first group turns it on.POST /api/partner/venues/{venueId}/connections/{connectionId}/exposeandPOST /api/operator/venues/{venueId}/connections/{connectionId}/exposeshow or hide a plugged-in provider to the venue’s own traders. Off by default.GET .../providersunder both families carriesavailable, the companies a venue may plug in.- A stage policy may carry
drawdown; the lock reasonsmax_drawdownanddaily_drawdownjoin the account snapshot. Both permanent, likeeval_breach. - The customer ledger read answers 404 for an account the venue issued on the paper book: its books are the paper book’s, and the analytics route on the account serves them.
2026-09-18: One structure, one glossary
Documentation only; no route changed. The site now uses one word per thing: venue, group, provider (built-in or public), login style, paper book, Demo, Connect, listed, level 2, Venue key, Trading API key, back office. Start Here opens with How trdrs fits together, and Build is filed by layer: trading platform, Connect, venue, providers, the Legacy Partner API, and the API standards. The Venue keys, Venue accounts and Get listed guides are new; the two onboarding orphans, the Connect and webhooks concept pages, the account-paths page and the two overview pages were merged into the guides that carry them, with redirects. The OpenAPI descriptions took the same words; tags, paths, parameters and schemas are unchanged.2026-09-18: Every provider declares how it is signed into
A provider’s login style is now part of its declaration, and Connect reads it instead of knowing each provider by hand. The six styles are the trader’s own login, OAuth, API key, wallet key, the firm’s credentials, and none./api/connect/providerslists the six built-in providers (Rithmic, Tastytrade, Hyperliquid, Binance, Bybit, the trdrs paper book) with theloginStyleeach declares and whether a trader login belongs to a named system. Keyless and static, like the Connect firm list.- Every row of the Connect firm list (
/api/connect/firms) carriesloginStyle, derived from the provider the tile opens. - A public provider’s manifest may declare
loginStyle. Omitted, it reads asfirm_credentials: the venue connects the provider with the firm’s own credentials and the trader types nothing. Every manifest written before the field validates unchanged.
2026-09-16: The firm’s accounts through the venue routes
Still the private preview: these are served on the sandbox. The venue API is now the one API a firm’s backend needs. The operations the legacy Partner API has always done on a firm’s accounts are reached through the venue, under both families, each behind a named venue-key scope, and each running the SAME operation the legacy route runs: same ledger-first ordering, same idempotency rule, same refusals. The legacy/api/partner/accounts… and
/api/partner/balance-op routes stay and are marked legacy in the reference, with their venue twin
named. Run firm accounts maps each call to its twin, and
Venue accounts walks the twins in order.
/api/partner/venues/{venueId}/accountslists the venue’s accounts (account:read) and issues one evaluation account into a group (account:issue). The group must have a route, else409 group_has_no_routebefore anything is issued; a venue with no adopted firm is404 no_firm./api/operator/venues/{venueId}/accountsis the session route family onto the same./api/partner/venues/{venueId}/accounts/{accountId}/balancecredits, debits or adjusts (balance:write). TheIdempotency-Keyis the firm’s referenceId; a repeat is409 duplicate_reference. Also/api/operator/venues/{venueId}/accounts/{accountId}/balance./api/partner/venues/{venueId}/accounts/{accountId}/resetresets to the starting balance under the newaccount:resetscope. Also/api/operator/venues/{venueId}/accounts/{accountId}/reset./api/partner/venues/{venueId}/accounts/{accountId}/haltand/api/partner/venues/{venueId}/accounts/{accountId}/resume(risk:halt), with a lock the firm does not own answered as409 lock_conflict. Also/api/operator/venues/{venueId}/accounts/{accountId}/haltand/api/operator/venues/{venueId}/accounts/{accountId}/resume./api/partner/venues/{venueId}/accounts/{accountId}/analyticsreads the account’s trading analytics (account:read), measured as the legacy analytics route measures them. Also/api/operator/venues/{venueId}/accounts/{accountId}/analytics.- Venue key scopes gain
account:reset. - The firm-operations half of the Partner API is being replaced by the venue API, group by group; Connect stays as the trader-facing module’s own API. Run firm accounts carries the status of each group and its venue twin; a group is marked legacy once the twin exists.
2026-09-16: The venue routes through a browser session
Still the private preview: these are served on the sandbox. Every venue configuration call is reached two ways, and the reference now lists both. A venue key authenticates a venue’s own backend at/api/partner/venues/…; a signed-in owner reaches the same
services at /api/operator/venues/… with a session cookie and a trusted Origin. Same validation,
same compare-and-swap, same refusals. A browser never holds a venue key, which is why the session
route family exists. Venue keys explains the split.
/api/operator/organizationslists and creates the organization that owns venues. A new one gets a non-login owning principal and the caller gets owner membership./api/operator/organizations/{organizationId}/venueslists that organization’s venues with the environment each belongs to, so nothing has to paste a venue UUID./api/operator/organizations/{organizationId}/memberslists who may operate them./api/operator/venuescreates a venue.environmentmust equal the environment the engine serves: an engine serves exactly one and refuses a body naming the other./api/operator/venues/{venueId}reads one./api/operator/venues/{venueId}/firmadopts the caller’s firm into that venue, with no body. It moves nothing: accounts the firm already issued keep the conditions they were issued under.firm_already_linkedandvenue_already_linkedare409; a caller with no firm is404 no_firm.
2026-09-14: Venue platform private preview (not publicly enabled)
Preview: served on the sandbox to every venue; production availability is arranged when a venue qualifies. Existingtrdrs_sk_… keys are unchanged;
the new scoped venue credential is trdrs_vk_sandbox_… or trdrs_vk_production_….
/api/operator/venues/{venueId}/keyscreates and lists keys through a verified owner session./api/operator/venues/{venueId}/keys/{keyId}revokes them. Bearer keys cannot manage keys./api/operator/venues/{venueId}/connections/{connectionId}/accountslists saved discovery without provider authorization references. Expired results and stale cursors require fresh validation./api/operator/venues/{venueId}/accounts/bindbinds a selected discovered account using its provider permissions. Retries recover the original binding; no trader grant, balance or trading readiness is created. Account-capable validation now acquires a session and saves complete discovery.- Provider setup is served under both families, with identical checks and different credentials:
a verified owner session reaches
/api/operator/venues/{venueId}/providers,/api/operator/venues/{venueId}/connections,/api/operator/venues/{venueId}/connections/{connectionId}/validateand/api/operator/venues/{venueId}/connections/{connectionId}/validations/{jobId}; a venue’s own backend reaches/api/partner/venues/{venueId}/providers,/api/partner/venues/{venueId}/connections,/api/partner/venues/{venueId}/connections/{connectionId}/validateand/api/partner/venues/{venueId}/connections/{connectionId}/validations/{jobId}with theprovider:manage,connection:manageandvenue:readscopes. Registering a provider contacts no endpoint. Creating a connection encrypts the credential and returns metadata only. Validation is a queued read-only job: the initiating key is rechecked before the fetch and again before the result commits, so revoked keys and lost ownership fail the job rather than finish it. A pass never clears a halt or makes the connection trading-ready. /api/partner/venues/{venueId}reads the key’s venue withvenue:read./api/partner/venues/{venueId}/instrumentsand/api/partner/venues/{venueId}/instruments/{candidateId}save/read immutable instrument candidates. Candidates do not activate a trading catalog./api/partner/venues/{venueId}/instruments/activelists and sets the version a venue dispatches against, withvenue:readandvenue:configure. Activation is a compare-and-swap onexpectedRevision(nullmeans no activation exists yet), and the version must keep a mapping on a live connection. A rename or an entry halt applies immediately; any other change is economic and requires every account bound to the venue to be provably flat in that instrument, with the blocking account IDs returned on refusal. Activating creates no grant, balance or trading readiness.- Venue conditions decide what an account is charged and what it may do.
/api/partner/venues/{venueId}/conditions/profilespublishes immutable profiles and/api/partner/venues/{venueId}/conditions/activeapplies one, by compare-and-swap./api/partner/venues/{venueId}/conditions/groupsdefines flat account groups,/api/partner/venues/{venueId}/conditions/accounts/{accountId}/groupmoves an account between them,/api/partner/venues/{venueId}/conditions/accounts/{accountId}/risksets per-account safety and/api/partner/venues/{venueId}/conditions/accounts/{accountId}/effectivereads the resolved answer with the layer that decided each value. Economics resolve by specificity and stop at the group; safety resolves by intersection, so a more specific layer can only ever tighten. A change that only tightens safety, or only renames, applies at once; a change to margin, commission, markup or financing requires the affected accounts to be provably flat and returnsnot_quiescentwith the blocking account IDs. Orders that add exposure are refused against these limits; reducing orders are not, so an account can always get out./api/partner/venues/{venueId}/conditions/previewanswers whether a proposed profile or group override changes economics at all, how many accounts it reaches and which are not ready, before the change is attempted rather than only when one is refused. It writes nothing. /api/partner/venues/{venueId}/routesdefines where a group’s orders go, internal or external, and/api/partner/venues/{venueId}/groups/{groupId}/routepoints a group at one. An external route names both its connection and its dedicated account; a half-configured route is refused at save. Moving a route’s mode, connection or account waits for the accounts on it to be flat. Retiring one stops it being offered to new groups and keeps it serving the ones already on it. There is no default route: an account whose group names none cannot open new exposure, though it can always close what it holds. A route also carries the collar every order sent through it has to fill inside - a count of the instrument’s ticks, or a share of the quote in basis points - along with the fee it reserves per unit and whether it may run an uncapped market order at all. An omitted collar is zero adverse ticks, which is the strictest reading and not “no collar”, anduncappedMarketAlloweddefaults to false and is refused on an internal route, where there is no provider cap to defer to. Widening a collar waits for quiescence like a mode change, because it changes the worst case of a trade already in flight. A buy is collared off the ask and a sell off the bid; the venue’s own markup is measured inside the same collar, so a markup reaching past it refuses the fill rather than charging more than the stated protection allows.- The whole venue configuration surface is served under
/api/operator/venues/{venueId}/...as well, to a verified owner session instead of a venue key. A browser must never hold a venue key, so an operator console has no way to reach the partner family; this is how it reaches the same routes. They are the same router with a different credential rather than a second copy, so the two cannot drift into two permission models. The session path additionally requires a verified email, and a caller who is not a member of the venue’s organization receives404rather than403, which would confirm the venue exists to somebody with no business knowing. A bearer key presented to the operator family is refused outright. /api/partner/venues/{venueId}/accounts/{accountId}/instrumentsreads the venue’s activated catalog resolved against one account: its conditions, its route and its open liquidation. A blocked instrument is returned with its reasons rather than omitted, so a trader who cannot find what was there yesterday can be told whether it was a halt, an allowlist, a retired route or a missing provider mapping. Every reason is an entry gate: a halted or de-listed account can still close what it holds. It answers configuration only: it cannot see a price, a balance or a stream, sobasisis alwaysaccount_configuration_onlyand an emptyblockedByis not a promise that an order will be accepted. An account belonging to another venue is refused rather than answered empty./api/partner/venues/{venueId}/accounts/{accountId}/ledgerreads a customer account’s balance, held collateral, positions and route, and/api/partner/venues/{venueId}/accounts/{accountId}/incidentreads its open liquidation with the reduction steps recorded against it. Both are scoped to the calling key’s venue, and the ledger exists only for accounts whose balance authority is TRDRS./api/partner/venues/{venueId}/stages/policiespublishes immutable stage rules and/api/partner/venues/{venueId}/stages/activeputs one in force, both withstage:advance. A stage rule is stored rather than supplied with the advancement request: a target that arrives with the question can be made easier by whoever asks it. It carries the profit target, the minimum trading days, the session timezone and rollover, the recorded risk breaches that disqualify a cycle, and the group a passing account lands in. A session timezone the runtime cannot resolve is refused at publication rather than at the first trading-day boundary. Moving the target waits for every account running that stage to be provably flat; changing only where a passing account lands applies at once, because it decides the next account rather than this one./api/partner/venues/{venueId}/conditions/groupsnow carries an optionalstageId, and moving a group onto a different stage is an economic change for the same reason./api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/eligibilityreads whether an account has passed, and/api/partner/venues/{venueId}/accounts/{accountId}/stages/{stageId}/advanceissues its successor. The decision is MEASURED from the account’s own books against the version in force, never supplied by the caller: a partner able to state its own net trading P&L could issue itself a funded account by describing one. Net trading P&L excludes allocations and balance operations and is taken after all fill fees; trading days are counted from when each fill actually traded rather than when it was booked, so a replay after an outage does not hand an account a day it did not trade; a fill whose source never said when it happened makes the window incomplete rather than counting as today.reasonslists every failing condition at once. The advance issues one successor per source cycle and stage - a second attempt with a different idempotency key returns the account the first one made - and it re-checks the version, the account’s revision and its quiescence before creating anything.startingAllocationis required andnullis a real value meaning a zero-balance successor. Only for accounts whose balance authority is TRDRS. A refusal is409 not_eligiblewith its reasons./api/partner/venues/{venueId}/accounts/{accountId}/grantsissues an invitation for an already bound account./api/partner/venues/{venueId}/accounts/{accountId}/grants/{claimId}reads or revokes it.grant:manageandaccount:readare separate permissions. Email alone never grants trading access, and accepting an invitation does not make a provider connection ready.
2026-09-12: Firm analytics and stage eligibility
GET /api/partner/accounts/analytics exposes current-cycle fill-derived net trading profit, fees,
session-based trading days, closed trades, open positions/orders, sampled equity, reset boundaries
and explicit completeness. Partner keys reach only accounts their firm issued.
GET /api/partner/accounts/eligibility checks a firm’s target and minimum days against complete
records, a flat account with no working orders/pending commands, no recorded disqualifying breach,
and a firm halt. It returns a stable reference for retrying next-stage account creation; it does
not advance or reset accounts. Legacy cycles with unknown risk history cannot auto-pass.
See Account analytics and stage eligibility.
2026-09-11: Sandbox firm branding
Set your firm’s name, description and PNG logo on the sandbox developer page before conformance.GET /api/account/list includes the provisioning firm’s identity for authorized accounts; trading
routes continue to use paper. See sandbox branding.
2026-09-11
- Free sandbox integration self-checks.
POST /api/partner/conformance/runsopens a two-hour run,GET /api/partner/conformance/runs/{id}returns measured results, andPOST /api/partner/conformance/runs/{id}/closefinalizes them. The sandbox observes the firm’s developer keys and tests handling of 429, 423 and a dropped stream. Other firms, browser sessions and traffic outside an open run are unaffected. Runs and evidence survive restart. No payment configuration is required. See Run a self-check.
2026-09-08
- An account says which symbols it can trade.
GET /api/account/instrumentsreturns the symbols the resolved account can trade through this engine, one row per tradable symbol with the search catalog’s own display identity (symbol,name,exchange,type), plus alabelfor the account: the firm or system name where the engine stores one (Apex), else the account number. The set is the venue’s own: a futures account lists the contract catalog, a crypto venue account lists that venue’s perpetuals, and the demo lists both. Additive, and it takes the samebroker/accountselectors and answers the same errors as the other account reads.
- Connect speaks registration. On
/api/partner/connect/accounts: the response fieldsclaimandclaimsare nowregistrationandregistrations,claimedAtislinkedAt, and the statusclaimedislinked(the full set ispending,linked,revoked,expired). The schema names follow (PartnerRegistration*). Routes are unchanged. - Webhook event types follow.
claim.claimedis nowregistration.linkedandclaim.revokedisregistration.revoked; their payloads carryregistrationIdinstead ofclaimId. The other event types are unchanged, and an endpoint registered with an empty filter receives the new names automatically.
2026-09-07
Breaking. The exit-plan placement shape changed, and this entry moves the compatibility baseline. There is no shim and no dual delivery. It lands before the first partner integration, which is why it lands at all; see Stability.- Protection is engine state, and it rides the account revision.
GET /api/account/snapshotandGET /api/account/streamnow carrybracketsandmanagedExits: every bracket the engine holds with its legs and their states, and every breakeven or trailing stop it is running, with the phase reached and the reason it is paused where it is. Both lanes carry the samerevisionas the rest of the account, so a protective change and the order change that caused it are points on one line.GET /api/account/bracketsandGET /api/account/managed-exitsserve the same two lanes for a surface that wants only one of them; a client holding a snapshot already has them. A leg inpre_armedis recorded and priced but deliberately not resting yet, because the position it protects does not exist; arming it also RE-PARENTS it, so a leg protecting a position carries a nullparentOrderId. - Saved exit plans are a principal-scoped catalog with conditional writes.
GET /api/exit-planslists the plans a trader holds andPOST /api/exit-plansauthors one.PUT /api/exit-plans/{id}andDELETE /api/exit-plans/{id}are CONDITIONAL: send back the opaquerevisionyou read, and a stale one is refused with409and the revision the plan carries now, rather than overwriting an edit that arrived in between. A revision is a digest, not a counter, so never construct one. Each plan reports the capabilities itrequires, so a host can tell which plans a selected account can run before offering them. - A plan is placed by reference, and the engine resolves its legs.
POST /api/account/exit-plans/previewprices the ladder from the account’s own instrument facts, says what it protects and what the order carries that it does not, and returns a token binding the ORDER: the account, the plan and its revision, the instrument, the side, the quantity and the entry.POST /api/trading/orderthen takesexitPlan: { planId, planRevision, previewToken }and no levels at all: the engine reloads the plan at that revision, re-resolves, and refuses an edited plan, a changed account, drift or an expiry. The resolved-leg request shape it replaces is gone, along with the browser arithmetic it carried. - The futures catalog states its fractional roots in executable form. A row of
GET /api/instrumentsfor a product the exchange quotes in thirty-seconds now carriespriceFraction:denominator, the number of parts one point divides into (32, 64 or 128), andsubFraction(2 or 4) where the writing divides one of those again. It comes from the same reading of the tick and the quotation convention that writes the fractional price format onGET /api/market/symbol-info, so a ticket sizes and snaps against the served fact rather than deriving a denominator of its own. A product quoted in decimals carries nopriceFractionat all. - The order warnings are named for the plan.
exit_plan_remainder_unplacedreplacesatm_remainder_unplacedandexit_plan_not_recordedreplacesatm_management_not_registered. Both still mean what they meant: the protected bracket is live either way, and the message says what did not happen. - A preview names the order it will be spent on.
POST /api/account/exit-plans/previewtakes theclientOrderIdthe placement will ride under, and the token binds it. A preview is therefore good for one submission rather than for any order until it expires. Generate the client order id before you preview and send the same one when you place. - The two protective one-shots carry the revision they were read at.
GET /api/account/bracketsandGET /api/account/managed-exitsanswer{ revision, items }. The number is the account’s current one, read rather than allocated: these reads do not advance the sequence your stream folds. - Exit plans are reachable with a tenant key. The catalog and the preview take a tenant key as well as a signed-in session, because a saved plan belongs to a principal and a key is one. A key reaches only its own plans.
- A capability descriptor says which parts of a plan the account can run. Every account frame’s
capabilitiescarriesexitPlanSupport: the subset ofstop_loss,take_profit,multiple_targets,runner_leg,breakevenandtrailing_stopthis account can execute. Compare it against a plan’srequiresto offer only the plans that will work.
2026-09-06
Breaking. The account stream changed shape, and this entry moves the compatibility baseline. There is no shim and no dual delivery. It lands before the first partner integration, which is why it lands at all; see Stability.- One event carries the whole account.
GET /api/account/streamsends oneaccountevent, on connect and on every change alike, and it carries the summary, the positions and the working orders as they were at one moment, with therevisionthat names that moment. Thesnapshot,positionsandordersevents are gone. A client that switched on those event names, or that merged them into a picture of its own, must be changed: subscribe toaccountand replace your whole picture with each frame. - Fold by the revision and nothing else. Hold the newest frame you have received for an
accountId. Drop a frame at or behind that revision. Replace everything with any frame ahead of it. A frame whose revision skips ahead is still complete, so there is no gap to detect and no resync to perform; a client written to resync on a jump should stop doing so. Never compute a revision of your own. GET /api/account/snapshotserves the same body. Read it when you have no stream open, or when you come back after a disconnect. Combining the one-shot summary, positions and orders reads is no longer the way to build a picture: three reads are three moments, and nothing in them says whether they agree.accountIdis how an account is named. It is an opaque token on every frame. Key panels, subscriptions and state by it; it is not a structure and must not be taken apart. An account number is unique at its own firm and nowhere else.capabilitiessays what the account supports. The frame carries what the broker adapter behind it implements, so you render only controls the venue can accept. A time-in-force absent fromtifsis refused, never mapped to a different lifetime.clocksays what the revision counts.enginemeans trdrs owns the account’s state and the number is the account’s own history.observationmeans the account lives at a venue and the number stamps our reading of it, so the order of readings is exact and the interval is not.positionModelsays the book is net. One instrument in one account holds at most one signed position, so a frame carries at most one row per instrument.
2026-08-29
- Connect makes the firm the only customer messenger. trdrs no longer sends account-ready
emails on a firm’s behalf.
POST /api/partner/connect/accountsno longer acceptshandover, its response no longer includesemailSent, and claim reads no longer includehandover. Requests that still send the retired field receive400; there is no compatibility shim. Firms notify traders and deliver venue credentials through their own secure onboarding process. This contract correction landed before the first partner integration and is the Connect compatibility baseline. - The futures contract catalog joins the licensed surface.
GET /api/instrumentsserves one row per futures product root (exchange, tick size and value, dollar multiplier, roll cycle, and the listed months of products whose roll is not modelled), the same static facts the trdrs order ticket sizes, snaps and prices with. Admission is the market-data model: your tenant key or your allowlisted origin. - Risk controls join the Account group.
GET /api/riskreads an account’s five risk controls (daily and weekly loss limits, daily and weekly profit targets, the end-of-day close) together with its lock state;PUT /api/riskreplaces the controls in one write, live from the moment it lands;POST /api/risk/unlockis the manual unlock. These are the controls behind every423 risk_lockeda trading route answers, and thelockobject is the same one that streams as thelockevent on/api/account/stream, so a front end holds one lock truth. Admission is the trading model exactly: your tenant key, acting as the accounts’ owner.brokeris required on all three;accounttargets one account under a multi-account login. - News and economic calendar join the licensed surface. A new News group in API Reference:
GET /api/news(aggregated market headlines, newest first, keyset-paged, scoped by futures root withinstrument),GET /api/news/stream(SSE:news_itemframes),GET /api/news/image/{id}(the keyless thumbnail proxy),GET /api/calendar(scheduled events in a bounded window, with impact tiers and display-string forecast/previous/actual), andGET /api/calendar/stream(SSE:calendar_updatenudges). News and the calendar each carry their own live stream. Admission is the market-data model exactly: your tenant key or your allowlisted origin.
2026-08-28
- Market data: one connection, many charts.
GET /api/market/streamsmultiplexes up to 24 bar subscriptions over a single SSE connection:subsis a comma-separated list ofINSTRUMENT~tftokens, every event payload carriesinstrumentandtffor demultiplexing, and a refused subscription becomes a tagged error event while the rest live on. Built for multi-chart layouts, where browsers cap concurrent connections per origin. - Market data: spread expressions are instruments.
/api/market/historyand the bar streams accept arithmetic over instruments, such asES-NQ,1/ESU6,(ES+NQ)/2; operators+ - * / ^, parentheses, numeric literals, up to four legs. The engine evaluates server-side over the bucket intersection of the legs; spread bars carry volume 0, and a string that matches a catalog symbol exactly is always that symbol, never arithmetic.
2026-08-24
- Webhooks: pushed events with signed delivery. A new Webhooks group. Register up to five
https://endpoints per firm withPOST /api/partner/webhooks(optionally filtered to specific event types), list them withGET, and remove one withDELETE. Six event types in v1:claim.claimed,claim.revoked,account.reset,balance.recorded,risk.locked, andrisk.unlocked. Every delivery is signed (trdrs-signature: HMAC-SHA256 overtimestamp.body, so a replayed payload cannot wear a fresh clock) and retried on failure for ~9 hours across 6 attempts.POST /api/partner/webhooks/testdelivers a signed ping right now and reports the outcome;GET /api/partner/webhooks/deliveriesis the per-endpoint delivery log (every attempt’s status, response code, and error, kept for 60 days), so “did you get it” is answerable from your side. - Firm accounts: risk controls, trading halt, and balance operations. The control half of the
Firm accounts group.
GET/PUT /api/partner/accounts/riskreads and sets the five per-account risk controls (daily/weekly loss, daily/weekly profit, end-of-day auto-close), the same controls the trader sees, enforced live by the risk monitor from the moment of the write.POST /api/partner/accounts/haltblocks all new orders until your firm’s ownPOST /api/partner/accounts/resume; the halt survives restarts, the trader cannot self-unlock it, and it never replaces a lock that is not yours.POST /api/partner/balance-opcredits, debits, or adjusts an account outside of trading, ledger-first on yourreferenceId, so a retried payout can never fire twice. - Firm accounts: provision and reset evaluation accounts by API. A new route group for partner
firms running traders on the trdrs venue.
POST /api/partner/accountsbatch-creates evaluation accounts for your traders by email (per-item results, idempotent on your ownreferenceId);GET /api/partner/accountslists the accounts your firm provisioned, with live balances; andPOST /api/partner/accounts/resetputs one back to its starting state, ledger-first so a retried reset can never fire twice. Every route is scoped to accounts your firm created through the API: an account the trader opened themselves is invisible here by construction. GET /api/partner/usage/accountsis live. The drill-down behind the usage number: each account that counted in the month, with the real fills that made it count and their first/last timestamps. Computed from the same query as the count, so the list always sums to the billed number: invoice reconciliation without asking us for a breakdown, account by account.GET /api/partner/usageis live. A firm can now pull its own metered usage for a month under its partner key: the distinct accounts that actually traded, the agreed per-account price, and the total. It is the same computation the trdrs invoice is built from, so a bill can be reconciled straight from the API. Scoped to the calling firm by its key, with no parameter that widens it, and read-only.- Keys, permissions, and data policy are documented. API Standards gained a Data policy page (what the engine stores, who sees what, and the per-trader market data rule), and the Keys page now covers all three permission levels, issuance, and revocation.
- Programmatic accounts. Operator Concepts gained a guide to running Connect claim
registration, listing, and revocation as an automated pipeline. Its initial
handovermodes were retired before the first partner integration on 2026-08-29. - The Quick Start examples now match the wire exactly. History takes
instrument,tf, andcountBack; orders takeinstrumentandorderTypewithbroker/accountas query parameters. The previous examples used field names the engine never accepted. - Worked examples on every operation. All 38 operations now render one coherent trading session instead of placeholder payloads: real ES prices, a fill that reappears in the executions ledger, an evaluation whose drawdown floors follow from its program’s terms.
- TypeScript and curl samples on every operation. Streaming routes show a real SSE reader, cookie-authenticated routes show first-party fetch, and every sample targets the production host with realistic parameter values.
- The spec’s first server is production (
https://app.trdrs.co), so generated snippets never point at a relative host.
2026-08-23
- The docs moved to this site. Overview, Quick Start, API Standards, Conformance, Operator Concepts, HTTP clients, and the API Reference now live in one place with one sidebar; old guide URLs redirect.
GET /api/market/configdeclares what the engine accepts: the timeframe grammar with per-unit ceilings, the bars/symbols/quotes limits, and the asset classes this deployment serves. A client can validate an ask without a round trip.- The Connect partner routes document the key that actually works there. Partner routes are
secured under the partner-scoped key in the spec itself; a tenant key is refused on
/api/partner/by design.
2026-08-22
- The prop evaluation surface returned as a PREVIEW group. Challenges and enrollments are
documented again, marked outside the additive-only guarantee, with the
CHALLENGES_ENABLEDgate stated on every operation. - The reference covers the whole licensed surface, grouped by tag (Market data, Trading, Account, Connect, Challenges), with an onboarding guide.
2026-08-14
- The holiday calendar is served.
GET /api/market/symbol-infocarries the session model’s holiday table (sessionCalendar), so clients never ship their own calendar updates. - Trailing stops became exclusively engine-managed. The broker-native
trailing_stopentry type is refused with a pointer at the ATM path, which manages trails identically on every venue.
2026-08-05
- Market data became licensed surface. The market routes answer first-party origins and authenticated principals only, and are documented under the tenant key.
Existing account inventory
GET /api/partner/venues/{venueId}/existing-accounts and GET /api/operator/venues/{venueId}/existing-accounts list prior issued accounts without venue bindings. The read requires account-read authority and changes no balances or trading rules. Cursor pagination includes at most 100 accounts per page.