{
  "openapi": "3.1.0",
  "info": {
    "title": "Kronos X Member API",
    "version": "2.43.0",
    "description": "Member API for the Kronos X MTF. Perpetual swap/future markets (kind PERP, margined, funded) and spot markets (kind SPOT, fully prefunded delivery of the base asset; since 2.25.2 the sandbox lists BTC-USD, ETH-USD, SOL-USD, BNB-USD and XRP-USD, sized on the same qtyStep as their perpetuals) trade side by side on one contract. Markets run in mode ORDER_BOOK (central limit order book) or RFQ (no book, trade by request-for-quote via POST /v1/rfq); barrier knock-out contracts (kind BARRIER) are RFQ-only, and so are yield contract markets (kind SWAP, 2.26.0; the fixed yield contracts of Member API section 6h): the WRITER posts a standing OFFER with POST /v1/rfq (rateBps, tenorDays, qty, minQty, validity), any other member TAKES a size with POST /v1/rfq/{rfqId}/accept (qty, no quoteId), the taker's principal in the market's asset moves to the writer at the take and principal plus a frozen reward return at maturity; contracts live under GET /v1/swaps and the WS swaps channel.\n\nAbout the examples on this page. Every request body below is offered as one or more NAMED examples; the interactive console prefills the first one and the dropdown above the body switches between them. Unless its name says otherwise, the first example of each endpoint is a body that EXECUTES against the listings as they stand: quantities on the instrument's qtyStep grid, prices on its tickSize grid and inside its price band, notional above the minNotional floor. Any example that needs a condition the venue cannot guarantee for you carries that condition IN ITS NAME as well as its description, so the dropdown alone tells you whether a body is ready to send: a FIXED-leverage instrument, an open position, resting liquidity on the other side, a live rfqId, a registered Authorised User, your own current Market Segments version, a barrier market without maxContractLifeHours. Four endpoints have no unconditional body at all and say so in the first entry: a market order needs someone else's order to trade against, a Market Segments write needs the version you just read, and the batch amendment and batch cancellation bodies (2.38.0) need the orderIds of your own open orders. Prices and barrier levels are anchored to the marks observed when this revision was published; if a market has moved, read GET /v1/mark-price (or GET /v1/ticker) and adjust before sending. THESE ARE LIVE ORDERS: a resting order stays on the book until you cancel it, and a marketable one trades.\n\nRate limits: two independent continuous-refill buckets per MEMBER, shared by every API key the member holds (up to 5 per scope; issuing adds a key, revocation is per key and immediate). Order placements, amendments and the entries of a placement or amendment batch all consume the order budget (each batch entry is one unit, charged up front for the whole batch); reads consume the read budget; cancels, the entries of a cancellation batch included, are never throttled. Holding several keys does not multiply the budget. A 1003 carries data.retryAfterMs.\n\nChangelog: 2.26.5 adds writer transparency (Member API revision 3.57), serialization only: GET /v1/rfq/open board rows, the writer's copy of a close request's WS rfq frames, WRITER rows on GET /v1/barriers (live and closed) and the WS barriers frames delivered to the writer gain capacity (OWN_ACCOUNT | FOR_CLIENT) and, on FOR_CLIENT rows, clientTag, a 16-lowercase-hex-char per-viewer pseudonym of the end client behind the flow (stable toward one viewer, unlinkable across members, the raw clientUid never crosses); requester and holder views are unchanged. Changelog: 2.23.0 adds the barrier EARLY CLOSE by RFQ, one optional request field, one error code and one trade flag, and changes nothing for a client that never sends closeContractId (it sees only new nullable members, omitted where they do not apply). POST /v1/rfq accepts closeContractId (int64): the id of an OPEN barrier contract you HOLD on symbol, making the request a CLOSE REQUEST to that contract's writer. side, qty and barrier must then be OMITTED (2013): the venue derives the closing side (a long holder SELLs, a short holder BUYs), the full contract quantity and the contract's terms; clientUid may be omitted (it defaults to the contract's holder-side client) or must equal it (2010); expiresInMs, clOrdId and reg behave as on any request. NEW code 2035 CLOSE_CONTRACT (400): closeContractId is not an open contract you hold on this market, or a close request for it is already open (at most one at a time; also the answer when the contract terminates between the steps). Only the contract's WRITER may quote a close request (anyone else is answered 2024, and it appears on the writer's board only: GET /v1/rfq/open and the WS rfq created frame, which the writer receives with role WRITER); the writer's price must be tick-aligned (2002), inside the band (2003) and STRICTLY INSIDE the contract's terms relative to the holder's direction, barrier < price < takeProfit for a long holder and mirrored for a short one, else 2027 (a price at or beyond the barrier would exceed the guaranteed maximum loss, at or beyond the take profit the guaranteed maximum gain). Accepting the quote (POST /v1/rfq/{rfqId}/accept) CLOSES the contract AT THE QUOTED PRICE: it prints a trade flagged BARRIER_CLOSE (a new value in the flags vocabulary, outranking RFQ) that pays maker/taker fees exactly like the entry (holder taker, writer maker, on qty x price x contract value), settles the contract BARRIERSETTLE zero-sum (holder P&L = direction x (price - entry) x qty x contract value, writer the negation) with terminationReason EARLY_CLOSE (new value on GET /v1/barriers closed rows and the WS barriers channel, whose frame type is earlyClose), then answers the accept with contractId (the CLOSED contract), closeContractId (echo), settlePrice and holder-signed realizedPnl beside the trade fields; no margin admission applies to a close (closing releases margin), the exact-money fence stays (2027). Every RFQ view (create answer, GET /v1/rfq/mine, GET /v1/rfq/open, GET /v1/rfq/quotes/mine and the quote answer, WS rfq frames) gains closeContractId (int64, omitted on an ordinary request). Coupling: while a close request is open the contract refuses a second one (2035); if the contract terminates first (knock-out, take profit, expiry, tear-up, final settlement) the venue CANCELS the open close request in the same command (an rfq canceled frame); cancelling a close request is free as any cancel. Changelog: 2.21.0 adds the funding SCHEDULE surface for the daily-settled tradfi perpetuals (equity indices, gold, oil, FX) and changes nothing for any request. GET /v1/instruments and GET /v1/funding/current (and the WebSocket get.instruments and get.funding reads) carry a funding block: schedule GRID (the historical fixed UTC anchor grid, intervalHours) or LOCAL_DAILY (one settlement per calendar day at a local wall-clock window: zone UTC | LONDON | NEW_YORK, snapshotLocalTime, vwapWindow, vwapSnapshots), plus nextSettlementTs (the same instant as nextFundingTs) and, on LOCAL_DAILY, nextSnapshotTs. Omitted on spot and barrier markets, which never fund. On a LOCAL_DAILY market the rate is not taken from a feed: at snapshotLocalTime the venue captures every open position and the index, over vwapWindow it records one mark per minute (vwapSnapshots of them, at the minute boundaries counted back from the window end), and at the window end it settles rate = clamp((mean of the recorded marks minus the index at the snapshot) / index at the snapshot, floor, cap), positive meaning longs pay, applied to the SNAPSHOT positions with the mean as the settle mark, so a position closed after the snapshot still pays that day and one opened after it pays nothing until the next. fundingIntervalHours reads 24 on such a market and fundingRateAnnualizedPct annualises over a day. predictedFundingRate, predictedFundingRatePct and predictedFundingPerUnit on GET /v1/funding/current, GET /v1/ticker and the WS funding rate frame are the running estimate from the marks recorded so far and are OMITTED (not null, never a fabricated zero) before the day's window opens. GET /v1/funding/history rows gain settlementValue, indexAtSnapshot, snapshotsUsed and snapshotTs on LOCAL_DAILY settlements (omitted on GRID rows), and the WS funding channel gains type settlementDetail carrying the same figures. A day on which the venue held no position snapshot (an outage across the snapshot time) is skipped, not charged later. 2.19.0 corrects and completes the close-attribution story after member feedback. GET /v1/lots/closures now includes ADL tear-ups: the ADL trade event deliberately carries no client identifiers (no end-client identifier crosses members), so the feed sources ADL closes from the per-client ADL record instead, attributed to the correct hedge bucket; the closeClOrdId for an ADL row derives as KX-ADL-{tradeId}. A defaulted member reconciles its own side through GET /v1/unwinds. And a statement correction carried through every document: liquidation and ADL executions always REDUCE, but a REVERSAL undoes the original trade, so a REVERSAL-flagged execution can carry positionEffect OPEN or INCREASE when the reversed trade had closed a position; always read the stamped positionEffect and never assume venue-initiated flow only closes. Changelog: 2.18.0 completes the member-integration transport coverage: FIX drop copy execution reports gain venue tag 9019 carrying positionEffect on fill legs (only ever set on trades, so non-fill reports stay byte-identical); GET /v1/ticker gains fundingPerUnit and predictedFundingPerUnit; GET /v1/funding/history rows gain fundingPerUnit computed from each settlement's own rate and mark. 2.17.0 (member integration asks): lot rows on GET /v1/lots gain openClOrdId and openOrderId (the member's OWN references on the opening fill, so lots are addressable by client-generated ids without a mapping table); new GET /v1/lots/closures serves the close-attribution feed (every closing fill mapped to the exact lots it consumed by the same FIFO fold as /v1/lots, with flags marking unsolicited liquidation/ADL/reversal closes); execution rows on GET /v1/executions and the WS execution frame gain positionEffect (OPEN, INCREASE, PARTIAL_CLOSE, CLOSE, FLIP: what the fill did to the client sub-position, so open versus close never needs inference); every funding surface gains fundingPerUnit and predictedFundingPerUnit (the charge for ONE unit of quantity at the current mark in the settlement currency per interval: multiply by position size locally instead of subscribing to per-position charges) (corrected in 2.40.0, Member API 3.83 section 7: a display figure rounded per lot, never the figure to multiply; reproduce a charge from fundingRate and markPrice). 2.16.0 adds one presentation value and no request surface: trade flags gain REVERSAL, produced when the venue exercises its rulebook cancellation and reversal power by booking an equal-and-opposite compensating trade at the original price between the same two members (reference KX-RV-{originalTradeId} on both legs, venue-generated, fee-free, excluded from order-to-trade ratios and from conditional-order triggering; the venue never edits or deletes the original trade record). Members see it wherever flags already appear: public trades, drop copy tag 9014, execution history and WS trade frames. A member whose trade is reversed additionally sees the compensating fill and its realized PnL ledger entry exactly like any fill. 2.15.1 is a DOCUMENTATION revision with no wire change and no behaviour change: the reg.tradingCapacity field description now states the venue semantics exactly (the field is spelled in the MiFIR vocabulary but is NOT MiFIR field 29: it declares the legal name of execution, DEAL own account, MTCH own name for a client account including commission business, AOTC agency in the name of the identified client; the RTS 22 report label derives from the configured per-member mapping and prudential bucketing keys on the venue semantics), closing the tagging trap for commission brokers whose home regime reports AOTC. The venue's RTS 22 extracts now carry per-leg field 29 report-label columns computed from the configured mapping at the extract edge, and the IFR data annex prints the capacity semantics as a methodology note. Member Technical Handbook 2.8 to 2.9 carries the same section. 2.15.0 adds one error code and states the production licensing posture; no request shape changes anywhere and nothing changes on the sandbox. NEW code 2034 (HTTP 403): in PRODUCTION the licensing registry runs FAIL-CLOSED, refusing order acceptance (order entry, RFQ create, quote and accept, lot close) for a member with no configured licensing profile, because profile configuration is a mandatory onboarding artifact; the SANDBOX stays fail-open and never answers 2034. Also venue-side with no wire impact: per-member RTS 22 field 29 report labels can be configured where a member's home regime reports matched principal differently; they change only the label the venue's transaction reports carry, never what you send and never the prudential bucketing, which keys on the capacity itself (own-name execution always accrues to dealing on own account, IFR Article 4(1)(33)); and the Art. 26 risk-factor buckets, Art. 29 supervisory factors, Art. 30 collateral haircuts and the SNI WARN share are seeded into the venue parameter store with citations pending compliance sign-off, preparing the Phase 2 exposure engines. 2.14.0 closes the RFQ classification gap 2.13.0 disclosed; no request shape changes and no field is added or removed on any endpoint. The reg object an RFQ QUOTE carries (POST /v1/rfq/{rfqId}/quotes) is now journaled on the venue's regulatory record exactly as the create's always was, and an acceptance stamps BOTH legs' records onto the trade, so RFQ and barrier executed value now classifies by trading capacity in the DTF/COH flow statements from this release forward. History cannot be reclassified: RFQ trades recorded before this release keep counting as UNKNOWN capacity, visible in the coverage percentage, because the quote-side capacity was never recorded for them. Quotes sent WITHOUT a reg object classify their maker leg as UNKNOWN, so RFQ makers should carry reg.tradingCapacity on every quote (capacity enforcement, where staged, already requires it). One engine-internal consequence with no wire impact: the venue's snapshot format version moves, so the first restart on this release recovers by full journal replay once. 2.13.0 follows an adversarial audit of the 2.12.0 capacity release, same day, and makes three corrections plus one addition; nothing else changes. (1) ADDITION: POST /v1/lots/{lotId}/close accepts an optional reg object with the same shape and rules as order entry, because a lot close IS order entry and a member under ENFORCE-stage capacity enforcement needs a carrier there or every lot close would reject 2033; without the field the close behaves exactly as at 2.12.0 for ungated members. (2) CORRECTION to the 2.12.0 wording on FIX OrderCapacity(528): the tag is read ONLY for members whose capacity enforcement stage is WARN or ENFORCE. For an ungated member (no licensing profile, or stage OFF) the tag remains entirely unparsed exactly as before 2.12.0, so the zero-change-at-OFF promise holds on FIX too; at WARN an unmappable or conflicting 528 is counted venue-side and ignored rather than refused, and at ENFORCE it refuses with 2033 as documented. (3) The portal Regulatory tab and the IFR data annex now state explicitly that RFQ and barrier executed value currently reports as UNKNOWN capacity (the venue does not yet journal the quote side's capacity; a later release will close this), that the capacity coverage percentage uses floor rounding and shows empty rather than 100.00 when a scope has no fills, and statement generation refuses loudly (PARAMETER_ERROR) instead of printing a fabricated 0.00 when the venue parameter store does not resolve. (4) Hardening with no wire shape change: venue parameter appends are validated (key shape, numeric families, bounded lengths and dates), the monthly annex of an empty month is a fixed deterministic form, and statement provenance reports one consistent engine incarnation and watermark pair. 2.12.0 activates staged validation of the EXISTING reg.tradingCapacity field and adds one error code; no field is added, removed or renamed, no default moves, and a member whose licensing profile has not been configured (or is configured OFF) sees zero change on any request. The venue operator can now record, per member, which MiFIR trading capacities (DEAL dealing on own account, MTCH matched principal, AOTC any other capacity) the member's licence permits, and stage enforcement per member: OFF (today's behaviour, the value is recorded verbatim and never validated), WARN (violations are counted on the venue side and surfaced to the operator, orders are NOT rejected), ENFORCE (a violating order rejects with the new code 2033 BEFORE it reaches the matching engine, like 1005/1003/2021). Under ENFORCE the rules are: reg.tradingCapacity is required on order entry, RFQ creation and RFQ quoting; the value must be DEAL, MTCH or AOTC exactly (the venue never normalizes or rewrites what you send); it must be permitted by your licensing profile; DEAL requires clientUid absent or your house reference (own-account flow rides the house account); MTCH and AOTC require a real end-client clientUid. Margin previews are reads and are never capacity-gated. FIX: standard OrderCapacity(528) is now ALSO accepted and maps P and G to DEAL, R to MTCH, A to AOTC; venue tag 9021 stays the canonical carrier, an unmappable 528 value is refused with 2033, and when both tags are sent they must agree (2.13.0 scopes this to gated members: at OFF the tag stays unparsed). Values recorded before enforcement, and orders recorded under OFF or WARN, are never reinterpreted: nonconforming history counts as UNKNOWN capacity in the venue's IFR flow statements, visible as the capacity coverage percentage on every statement. The same release adds the member portal Regulatory tab (daily DTF/COH flow statements, rolling K-DTF and K-COH input measures, the monthly IFR data annex v1 unsigned download), served from the venue's projections; those are portal surfaces, not REST endpoints, and this document is unchanged by them. 2.11.2 is a DOCUMENTATION revision with no wire change and no behaviour change: the clientUid description now states the identifier economics (the venue-wide end-client table caps at 1,048,576 identifiers and is never pruned, so send one STABLE identifier per real end client, never a fresh value per session; clOrdId is the per-message reference), matching the warning the member reference now carries where clientUid is introduced. 2.11.1 fixes the lot-fold narrowing remedy and publishes the fold bounds. The 2013 refusal for the funding-attribution work bound on GET /v1/lots has always said to narrow the query with positionSide, but a narrowed fold previously attributed funding across all three buckets anyway, doing identical work and refusing identically; a filtered fold now processes only the requested bucket (buckets are independent, so no returned figure changes) and starts its settlement count at that bucket's first fill. No wire shape changes; the only behaviour change is that narrowed queries which previously refused now succeed, as the message always promised. The bounds are now numeric in this document: at most 100,000 fills per (clientUid, symbol) scope, at most 20,000 funding settlements to attribute (about 18 years of an 8 hour grid, counted from the first fill the fold covers), and at most 5,000,000 attribution steps (settlements x lots open at each); past the settlements bound, or when a single bucket alone exceeds the work bound, there is no in-API remedy: reconcile that client by positions and executions, and note POST /v1/lots/{lotId}/close is refused for such a scope too. 2.11.0 is ADDITIVE. No field is removed or renamed, no default moves, no code changes meaning, and every request that worked at 2.10.1 works identically; the only reason to re-read is that funding was being misread. (1) RATES ARE FRACTIONS, NOT AMOUNTS. fundingRate has always been a dimensionless fraction of position notional PER INTERVAL (0.0001 is 0.01% per interval, so a 100000 USD long pays 10 USD per settlement) and has never been a currency amount, but nothing on the wire said so. Every surface that publishes a rate now also publishes fundingRatePct, the same number scaled by 100, and fundingRateAnnualizedPct, rate x (365 days / fundingIntervalHours) x 100 with no compounding, for comparison against other venues: GET /v1/funding/current (which also gains fundingIntervalHours), GET /v1/ticker, GET /v1/funding/history and the WebSocket funding channel on both the rate and settlement frames. The annualised figure is OMITTED (not null, and never 0) where a market has no funding grid, because a fabricated zero reads as a market that costs nothing to hold. (2) THE CURRENCY IS NAMED. Funding PAYMENTS are the currency-denominated half, booked in the instrument's settlement currency, and settlement is per instrument rather than venue-wide. GET /v1/positions and GET /v1/positions/end-clients rows now carry settleCcy, the currency their unrealizedPnl, realizedPnl and accFunding are expressed in, and the funding and lots surfaces carry it too. Today every listed market settles in USD; do not hard-code that. (3) FUNDING ON LOTS. GET /v1/lots and POST /v1/lots/{lotId}/close now report financing. Each lot carries accFunding, what it has been charged since it opened, and fundingIntervals, how many settlements it has been open across. The venue charges funding on the client sub-position NET, once per anchor, never per lot, so the per-lot figure is an attribution of a booked charge: each anchor charges exactly the lots open when it settled, and the shares sum to the charge on the bucket net to the micro, with the rounding remainder booked to the largest lot exactly as the venue books it to the largest client. Financing follows the quantity actually held, so a partially closed lot keeps what it incurred while it was larger and a fully closed lot takes its financing with it. The envelope therefore publishes three figures and you should read all three: accFunding is what the venue BOOKED on the sub-position and is the one to reconcile client statements against, openLotsFunding is what the listed lots carry, and closedLotsFunding is the difference. A client with very long funding history and very many open lots can exceed the attribution work bound, which rejects with 2013 and a message telling you to narrow the query with positionSide. 2.10.1 was a DOCUMENTATION revision with no wire change and no behaviour change: no field, endpoint, code or default moves, and every request that worked at 2.10.0 works identically. It states explicitly what reduceOnly has always done, because the wording invited a wrong reading. The reduce-only budget is judged against your MEMBER NET position on the instrument and is never judged against an end client's sub-position, since venue risk logic never reads client sub-positions. For a broker the consequence is that an end client closing its OWN position while the member book leans the other way is refused 2008 even though that client genuinely holds it, and a perfectly netted member book (member net exactly zero) refuses EVERY reduce-only order on that instrument from either client on either side. reduceOnly is a MEMBER risk control, for example a risk desk flattening the house book during a margin call, and it is NOT a client close tool: send end-client closes as plain orders gated on the client's own row from GET /v1/positions/end-clients, which is also why POST /v1/lots/{lotId}/close defaults reduceOnly to false. The reduceOnly and CloseLotRequest field descriptions now say so. 2.10.0 adds the lot surface, one new error code and the queue-position echo, and changes nothing for any request that does not use them. GET /v1/lots?clientUid=&symbol=&positionSide= returns an end client's open position as the individual opening fills (lots) that built it, oldest first, folded on demand from the fill history per (clientUid, hedge bucket, instrument): every bucket-increasing fill opens a lot (lotId = the opening fill's tradeId, entry = its price), reducing fills consume explicitly assigned lots first and then FIFO from the oldest, and a fill through zero closes everything and opens one opposite-direction lot with the remainder; served from the projection store (asOfSeq is the store watermark), at most 100000 fills per clientUid and symbol (past the bound the fold refuses with 2013). POST /v1/lots/{lotId}/close closes one lot: a MARKET IOC on the opposite side for the lot's remaining quantity, tagged with the lot's hedge bucket, with an assignment recorded so the fold consumes THAT lot first; a lotId that is not an open lot of that clientUid and symbol answers the new code 2032 (HTTP 404), and reduceOnly on the close is applied only when sent, default false, because the reduce-only budget is member-level. Lots are a DISPLAY convention: the engine keeps no lots, margin and liquidation and the venue's booked realized PnL stay average-cost per sub-position, and per-lot realized attribution is presentational, which is why the surface reports open lots only (corrected in 2.39.0, Member API 3.80 section 6e: this note said per-lot unrealizedPnl summed exactly to the sub-position's; it does so only until a partial close leaves lots at different entry prices). Queue position: when a placement RESTS an order, the place ack and the ORDER_ACCEPTED order frame carry queueQtyAhead (decimal string, the quantity resting ahead at the order's price level in FIFO priority) and queueOrdersAhead (integer, orders ahead at that level); a first order at an empty level reports 0 in both, PRESENT, meaning front of the queue, and the fields are OMITTED, not null, wherever no queue position exists (full fills, IOC/FOK/market remainders, pending-trigger accepts, rejects, amends, history reads), so every pre-queue payload stays byte-identical. The figures are a snapshot at the moment of rest and immediately stale; the venue never updates them. The same venue release ships cancel-on-disconnect on the WebSocket (session.cancelOnDisconnect op) and FIX (Logon tags 9004/9005), which this document does not describe since it covers REST only. 2.9.1 extends hedge mode to order history and describes that route here for the first time. GET /v1/orders/history rows now carry the optional positionSide (LONG or SHORT), OMITTED (not null) on netting orders, exactly like the live order surfaces 2.9.0 shipped, so every pre-hedge history row stays byte-identical; and the route itself (closed orders AND rejections, the only place a rejection that never reached the book can be re-read after the fact, newest first, served from the projection store with the envelope asOfSeq as the store watermark, limit default 100 clamped to 1 to 1000) is now described in this document with its row schema, having previously been documented in the REST integration manual and on the documentation site only. No request shape changes anywhere, no WebSocket or FIX change, and no other endpoint changes. 2.9.0 adds hedge mode, one new OPTIONAL order field and its echoes, and changes nothing for any request that does not send it. positionSide (LONG or SHORT) on order entry (POST /v1/orders, every POST /v1/orders/batch entry, the WS order.place and orders.batch ops; on FIX the same value rides the new venue tag 9016) routes the order's fills to that BUCKET of the order's clientUid sub-position, so one end client can hold a long and a short sub-position in the same instrument at once: at most one LONG, one SHORT and one netting sub-position per clientUid per instrument, and netting applies INSIDE the bucket, so a BUY tagged SHORT reduces the short bucket. ABSENT means netting, exactly as before the field existed; the default is unchanged and the field is strictly additive. Order-book perpetual markets only: positionSide on a spot instrument rejects 2016, a value other than LONG or SHORT rejects 2013, and RFQ and barrier flows do not take the field in this release. MEMBER-LEVEL MARGIN IS COMPLETELY UNAFFECTED: the member position stays the net sum over all buckets, risk never reads sub-positions, and hedged client flow nets at member level for margin exactly as it always did; funding attribution, liquidation allocation and final settlement operate per sub-position exactly as they always did per client, bucket by bucket, and reduceOnly composes with positionSide (the reduce-only budget stays member level). Echo contract: acks, open-order reads and order events carry positionSide back, OMITTED (not null) for netting orders, so every pre-hedge payload stays byte-identical; GET /v1/positions/end-clients rows now carry positionSide (LONG or SHORT, omitted on netting rows), one row per bucket. 2.8.0 adds the client identity surface for transaction reporting (RTS 22), three routes and two error codes, and changes nothing on any existing endpoint. PM MTF Ltd owes transaction reports under MiFIR Article 26(5) for members that are not MiFID II investment firms; where such a member's trade carries client flow, the venue's report needs the underlying client's RTS 22 Annex I Table 2 identification, and these routes are how members supply it, keyed by the clientUid already stamped on every order and DECOUPLED from order entry. PUT /v1/clients/{clientUid}/identity upserts the record (strict body like order entry, unknown field 2017; requires a trading-capable credential, READ_ONLY keys answer 1005; every PUT appends an immutable audit revision and the response carries the monotonic revision); GET /v1/clients/{clientUid}/identity reads it back (2031, HTTP 404, when none); GET /v1/clients/identity/missing lists the distinct clientUids of yours that traded on MiFIR-scope (perpetual) markets in the window with no record on file, the chase list for the T+1 reporting deadline (default window the last 48 hours, limit 1 to 1000 default 500; the envelope asOfSeq is the projection watermark, so a trade acked a moment ago may not be visible yet). Trading is NEVER blocked on identity data. The stored record carries mifirId, the identifier the venue's report will carry, resolved at submission time (the LEI for a legal entity, the national identifier for a natural person, else the derived RTS 22 CONCAT code) and reported as mifirIdSource LEI, NATIONAL_ID or CONCAT. A market maker can register its own LEI against its house UID so own-account sides resolve too; MiFID II firms report their own transactions and are unaffected. New codes: 2030 CLIENT_IDENTITY_INVALID (400, the message names the offending field), 2031 CLIENT_IDENTITY_NOT_FOUND (404). Deployments without the venue's history store answer 5004/503 on all three routes. 2.7.5 adds one error code, 2029 CLIENT_LIMIT, and narrows one published retention rule; no field is added, removed or renamed and no request body changes. (1) 2029 means the venue cannot register a clientUid it has never seen because its end-client identifier table is full. The bound is 1,048,576 distinct identifiers venue-wide against roughly 50,000 in use, so it is not reachable at any realistic client count; orders and RFQ acceptances quoting an identifier the venue already knows are never affected, and nothing is deleted to make room, because an identifier carries lifetime realized PnL and funding for that end client. Treat it as a signal that a client-identifier generator is producing a fresh value per message: clientUid is the ultimate client stable reference, clOrdId is the per-message one. (2) The idempotency record for a clOrdId is now bounded by COUNT as well as by age: the venue retains the most recent 4,000,000 references venue-wide, or 24 h, whichever is reached first. Your obligation is unchanged (unique per member per 24 h) and every behaviour inside the horizon is unchanged: an identical resend still returns the original order with duplicate true, and a different payload on a live reference is still 2009. What changes is only what a RELEASED reference does, and only when venue-wide volume reaches the bound before 24 h elapses: it behaves exactly as one that aged out, so resending it places a new order and reusing it with a different payload no longer rejects. A reference whose order is still working or pending trigger is never released, so cancel and replace by clOrdId stay available for the whole life of the order, including past 24 h, which they previously did not. Retry loops act within seconds and are unaffected; reconcile long-running state by orderId or GET /v1/orders rather than by resending. 2.7.4 finishes what POST /v1/margin/preview (and the WebSocket get.marginPreview op) answers, in the one admission rule it still did not mirror and in the codes it answers with. (1) accepted now answers the REDUCE-ONLY BUDGET. A reduceOnly order can only close what you actually hold: the venue admits one only while the reduce-only quantity already working on that market, plus the new order, stays within your open position on the reducing side, and rejects the surplus 2008. The preview did not apply that rule at all, so a reduce-only basket that over-closes (two SELL 100 reduceOnly entries against a 100 lot long, say) answered accepted: true while sending it would have placed the first entry and rejected the second, in exactly the margin-call situation the reduce-only exemptions exist to serve. The basket is now measured as a whole against what is left to close, so the answer is independent of the order you send the entries in, and an entry on the side that would ADD to your position, or on a market where you hold nothing, is reported rejected rather than accepted. What accepted still does not answer is venue state that is not a property of your basket: halts, member or instrument status, and whether a market order would find liquidity. (2) An entry the venue would reject OUTRIGHT now answers with the same code order entry answers, rather than a blanket 2002 or a bare accepted: false: a reduceOnly entry or a market-type conditional BUY on a spot market answers 2016, an out of range trigger price or post-trigger limit price answers 2013, a market with no sequenced mark yet answers 3005, and a limit priced at zero answers 2002. Admission gates are unchanged and still answer accepted: false, which is what accepted is for; only the checks order entry makes BEFORE admission became codes. (3) An entry that fails the per-order size cap no longer contributes to the reported im, mm and available. That cap is the bound that makes those figures computable at all, so they now describe the entries that could actually be staged, with accepted false exactly as before. Request bodies are unchanged and no field is added, removed or renamed. 2.7.3 corrects what POST /v1/margin/preview (and the WebSocket get.marginPreview op) ANSWERS, so that it agrees with what sending the same basket would do. (1) A MARKET entry is valued at the current mark on every market kind. A perpetual market entry always was; a SPOT market BUY was valued at ZERO, so its prefunding need vanished and a basket the venue would reject for insufficient funds could come back accepted. The mark is the price the venue already values a market order at for the per-order cap and the minNotional floor; the collar a market order actually takes forms from the book at the instant of entry, so no read can reproduce it. (2) reduceOnly entries are no longer held to the available gate. Placement deliberately skips that gate for a risk-reducing perpetual order, so a broker previewing a reduce-only basket during a margin call was told it would be rejected at exactly the moment the answer mattered most; it now answers accepted, as sending it would. reduceOnly remains exempt from the minNotional floor and the position cap, and remains subject to the per-order size cap, entry by entry, exactly as placement applies them. (3) accepted now also answers the per-order size cap (2013), the minNotional floor (2028) and the position cap (2011) over the whole basket, so a basket that would be rejected on size is reported as rejected instead of accepted. What accepted still does not answer is venue state that is not a property of your basket: halts, member or instrument status, the reduce-only budget, and whether a market order would find liquidity. The served response schema still said the figures described the FIRST entry only, contradicting the basket pricing 2.7.2 shipped; it now describes the basket. The preview remains a read: nothing is placed, nothing is reserved, and no order-budget unit is consumed. Unrelated to the preview and not reachable at any real balance: the equity and available figures on GET /v1/account now saturate at the venue's exact-money ceiling (1e18 settlement-currency units, the same ceiling per-order notional carries) rather than at a lower internal bound, so a figure inside the range the venue represents exactly is never reported, or admitted against, as a clamped value. 2.7.2 makes POST /v1/margin/preview (and the WebSocket get.marginPreview op) price the orders array as ONE BASKET. Previously the figures returned described the first entry only, additional entries were validated but did not move im, mm or available, and the published documentation said so; now every entry participates, perpetual entries fold into order margin together with the same one-sided max(buy, sell) netting per instrument that resting orders receive, spot entries have their prefunding needs summed per currency, accepted answers every gate at once, and the result is independent of array order. Single-entry previews are unchanged. New cap: at most 50 entries per preview, the batch limit, above which the request rejects with 2002. 2.7.1 aligns the reduceOnly echo on event-derived order payloads: place and cancel acks (REST and WebSocket, single and batch), WS order frames and newly stored stream backfill rows now echo the order's actual reduceOnly flag; previously they always reported false even on a reduce-only order, while state reads (GET /v1/orders/open, GET /v1/orders/{orderId} for a working order) were already correct. Enforcement was never affected, no field is added or removed, requests are unchanged. 2.7.0 adds an absolute per-order size ceiling that applies on every market, on top of whichever per-order cap that market publishes: one order's price times qty must stay within the venue's exact-money range (1e18 settlement-currency units), or it rejects 2013. It sits far above every published maxOrderNotional and far above any order a member would send, and it is what guarantees that every trade, fee and position update the venue books is exactly representable, since a fill always executes at the RESTING order's own price. The cancelReason set gains POSITION_SIZE_LIMIT for the matching guarantee one level down: if settling a fill would take a position beyond that same range, the order is canceled instead of settling a position the venue cannot describe exactly. Neither is reachable at any tradable size; they are stated so the contract is total. 2.6.3 adds one error code, 5005 COMMAND_FAILED, and changes nothing else. It means the venue accepted and durably recorded your command and then could not finish processing it; trading continues normally. On order entry it arrives like every other engine rejection, as data.rejectCode inside a 200 with code 0, and the rest of data reports what the command DID achieve before it stopped, so an orderId there is a real order that may be resting or partially filled. Reconcile against it and GET /v1/orders/open, and never resubmit the identical request: the venue is deterministic, so an unchanged resubmission fails identically. 2.6.2 is a documentation revision with no wire change: every operation now declares a typed 200 response schema (the same Envelope-plus-data composition GET /v1/instruments already used) and a stable operationId, so generated clients get typed responses and stable method names across the whole surface. No payload changed shape; the schemas describe the responses as they have always been. 2.6.1 is a documentation revision with no wire change. Every request-body and parameter example was re-checked against the live listings and reissued as named examples: the default POST /v1/orders body is now a minimal limit order that executes, and the optional leverage assertion, the trigger block, the GTD expiry and the regulatory fields moved out of it into separate named examples labelled with the condition each one needs (in particular, a leverage assertion is only ever accepted on an instrument with leverageMode FIXED, and no instrument listed today runs one, so that example rejects with 2018 until one is listed). Batch entry, margin preview, amend, Market Segments, RFQ creation, RFQ quoting and RFQ acceptance gained the same treatment; hard-coded absolute expiry timestamps that would have gone stale were removed or moved far into the future. Two examples whose outcome depends on something outside the request now carry that condition in their names rather than claiming to execute: the market order, which returns status REJECTED with rejectCode 2007 when nothing rests on the other side, and the Market Segments write, whose version field must be the one GET /v1/market-segments just returned or the write returns 4001 and changes nothing. 2.6.0 makes the per-order size cap notional too: GET /v1/instruments adds maxOrderNotional (per-order cap as a decimal settlement-currency string, omitted when not set). When present, code 2013 is enforced by valuing each single order at its effective price (priced orders at the limit price, market orders and RFQ creation at the current mark, RFQ quotes at the quoted entry) against that cap, and maxOrderQty becomes informational legacy; when absent, the maxOrderQty unit cap applies unchanged. The order cap applies to reduceOnly orders as well (a fat-finger guard applies to closes; closing a large position may take several orders), while venue-initiated closes (liquidation, ADL) are exempt. 2.5.0 makes position caps notional for uniform dollar capacity across markets: GET /v1/instruments adds maxPositionNotional (position cap as a decimal settlement-currency string, omitted when not set). When present, code 2011 is enforced by valuing your projected worst-case position at the CURRENT mark against that cap, and maxPositionQty becomes informational legacy; when absent, the maxPositionQty unit cap applies unchanged. A position that ends up above the cap because the mark moved is never forced to reduce; the cap only gates increases (risk-reducing flow always passes). maxOrderQty is unchanged and stays a per-order size guard. 2.4.0 adds batch order entry: POST /v1/orders/batch (and the WebSocket orders.batch op) submits 1 to 50 complete, independent orders in one signed message, each with its own clOrdId and clientUid; entries execute in array order, results return in array order, the batch is non-atomic, and it consumes one order-budget unit per entry, all or nothing. 2.3.0 (ships with a venue data reset) introduces base-unit contract sizing: quantities are decimal BASE ASSET UNITS aligned to the instrument's qtyStep (old integer quantity strings remain valid), prices stay quoted per base unit and LOOK unchanged, GET /v1/instruments adds qtyStep, minQty and minNotional, and orders or RFQs whose price times qty falls below minNotional reject with the new code 2028. 2.2.0 added the RFQ trading surface and barrier knock-out contracts. The spec version is bumped on every member-visible surface change.\n\nAll prices, quantities, rates and amounts are exact decimal STRINGS, never floats. Quantities are decimal base-asset units on the instrument's qtyStep grid; prices are per base unit on the tickSize grid; misaligned values reject with 2002, the venue never rounds. Timestamps are Unix milliseconds. Every response carries asOfSeq, a strictly monotonic venue-wide sequence number you can use to order data across REST and WebSocket.\n\nPrivate endpoints are authenticated per request:\n  signature = hex(HMAC_SHA256(secret, X-TIMESTAMP + METHOD + pathWithQuery + body))\nsent as X-API-KEY, X-TIMESTAMP, X-SIGNATURE. Use the Authorize button on this page to have the browser compute them for you.\n\nSince 2.42.0 (Member API revision 3.85, section 3) a signed write is accepted ONCE: the same X-API-KEY and X-SIGNATURE on any method but GET (POST /v1/margin/preview, a read, excepted) answers 401 code 1002 (request already received), so sign every send, a retry included, with a fresh X-TIMESTAMP and keep its clOrdId; a node also refuses 1002 a signed write stamped before it began to accept writes. The optional X-RECV-WINDOW is an integer from 1 to 60000 ms (default 5000; any other value is refused 1002, never reduced); X-TIMESTAMP may lag the venue clock by up to the window and lead it by at most the smaller of the window and 5000 ms."
  },
  "servers": [{ "url": "https://sandbox.mtf.perpetuals.net" }],
  "tags": [
    { "name": "DLT Market", "description": "Tokenised securities under Regulation (EU) 2022/858 settled on the Kronos X chain (Member API 3.66, section 6i): your wallets, custody transfers, unlocks, signed instructions, settlement obligations, and the public record /chain/v1/*." },
    { "name": "Public market data", "description": "No credentials required." },
    { "name": "Trading", "description": "Order entry and management." },
    { "name": "Lots", "description": "CFD-style per-client lot view, folded on demand from the fill history. A display convention: the engine keeps no lots." },
    { "name": "RFQ", "description": "Request-for-quote trading and barrier contracts (RFQ-mode markets)." },
    { "name": "Account and positions", "description": "Balances, margin, member and end-client positions." },
    { "name": "Client identity", "description": "RTS 22 identification data for the venue's MiFIR transaction reports, keyed by clientUid and decoupled from trading." },
    { "name": "Market Segments", "description": "Counterparty acceptance (liquidity pools)." },
    { "name": "Risk", "description": "ADL indicator and unwind episodes." }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": { "type": "apiKey", "in": "header", "name": "X-API-KEY" },
      "Timestamp": { "type": "apiKey", "in": "header", "name": "X-TIMESTAMP",
        "description": "Unix ms, signed. Since 2.42.0 it may lag the venue clock by up to the receive window (X-RECV-WINDOW, an unsigned optional header, an integer from 1 to 60000, default 5000, any other value refused 1002) and lead it by at most the smaller of the window and 5000 ms; a signed write is accepted once, so every send is signed with a fresh value." },
      "Signature": { "type": "apiKey", "in": "header", "name": "X-SIGNATURE" }
    },
    "schemas": {
      "Envelope": {
        "type": "object",
        "properties": {
          "code": { "type": "integer", "example": 0, "description": "0 on success, otherwise a registry code." },
          "msg": { "type": "string", "example": "ok" },
          "data": {},
          "asOfSeq": { "type": "integer", "format": "int64", "example": 918273 },
          "ts": { "type": "integer", "format": "int64", "example": 1785470168892 }
        }
      },
      "PlaceOrderRequest": {
        "type": "object",
        "required": ["symbol", "side", "type", "tif", "qty", "clientUid"],
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY" },
          "type": {
            "type": "string",
            "enum": ["LIMIT", "MARKET", "STOP_MARKET", "STOP_LIMIT", "TAKE_PROFIT_MARKET", "TAKE_PROFIT_LIMIT"],
            "example": "LIMIT"
          },
          "tif": { "type": "string", "enum": ["GTC", "IOC", "FOK", "POST_ONLY", "GTD"], "example": "GTC" },
          "expireTs": { "type": "integer", "format": "int64", "example": 1893456000000,
            "description": "GTD only, Unix ms, and it must be in the FUTURE at the moment the venue sequences the order (a past or equal timestamp rejects with 2013). On any other tif the value is accepted and recorded but never acts: only tif GTD is expired by the venue, so an expireTs on a GTC order does NOT make that order expire. 2.43.0 (Member API 3.86): a GTD order never trades at or after expireTs, measured against the time the venue sequences each command, never your clock. From that instant an incoming order or a call auction's uncross that reaches it expires it instead of trading it (status EXPIRED, exactly as the venue's expiry sweep reports it), a conditional reaching its trigger expires instead of triggering, and an amendment or a cancellation of it answers 2014 and expires it (a cancel-all expires it among the orders it ends); an order nothing reaches is reported EXPIRED by that sweep, which runs about once a second. The matching engine applies this from its replay-contract line for Member API 3.86, the first command of a venue started on the production contract; venue operations announce the date on any environment where that line lies ahead. Before that line the sweep alone expired it, and it could trade until the sweep reached it." },
          "price": { "type": "string", "example": "69000",
            "description": "Per base unit, on the instrument's tickSize grid (else 2002; a string that is not a decimal numeral at all, an exponent, a blank, letters, is the shape error 2013 since 2.26.8). Required for LIMIT. Omit for MARKET. A limit price further than the instrument's priceBandBps from the current mark rejects with 2003, so anchor it to GET /v1/mark-price rather than to a number copied from this page." },
          "qty": { "type": "string", "example": "0.001",
            "description": "Decimal base-asset units, an exact multiple of the instrument's qtyStep (else 2002: zero, negative, finer than or off the grid; a string that is not a decimal numeral at all, an exponent such as 1e-4, a blank, letters, is the shape error 2013 since 2.26.8); integer strings remain valid. price times qty below the instrument's minNotional rejects with 2028." },
          "reduceOnly": { "type": "boolean", "example": false, "description": "Perps only, rejected on spot (2016). MEMBER RISK CONTROL, NOT A CLIENT CLOSE TOOL. The reduce-only budget is judged against your MEMBER NET position on the instrument and NEVER against an end client's sub-position, because venue risk logic never reads client sub-positions. Consequence for a broker: an end client closing its OWN position while your member book leans the other way is refused 2008 even though that client genuinely holds it, and a perfectly netted member book (member net exactly zero, say one client long 10 against another short 10) refuses EVERY reduce-only order on that instrument, from either client, on either side. Use this flag when you want a venue-enforced guarantee that an order can only SHRINK your own house exposure, for example a risk desk flattening the member book during a margin call. For an END CLIENT close, send a PLAIN order without this flag and gate it on that client's own row from GET /v1/positions/end-clients: only you know your client-level book. This is also why POST /v1/lots/{lotId}/close defaults reduceOnly to false." },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "example": "LONG",
            "description": "Optional, hedge mode: routes this order's fills to the LONG or SHORT sub-position bucket of the order's clientUid, so one end client can hold a long and a short sub-position in the same instrument at once (at most one LONG, one SHORT and one netting sub-position per clientUid per instrument; netting applies inside the bucket, so a BUY tagged SHORT reduces the short bucket). ABSENT means netting, exactly as before the field existed. Order-book perpetual markets only: rejected with 2016 on a spot instrument, 2013 on any other value; RFQ and barrier flows do not take the field. Member-level margin is unaffected: the member position stays the net sum over all buckets and risk never reads sub-positions. Echoed on acks, open-order reads and order events, OMITTED (not null) on netting orders. reduceOnly composes with it; the reduce-only budget stays member level." },
          "clOrdId": { "type": "string", "maxLength": 36, "example": "my-order-1",
            "description": "Your order reference. Unique per member per 24 h, echoed on every response and notification for this order. Strongly recommended but not enforced: an omitted or empty clOrdId is accepted and simply gets no duplicate protection. Reusing a clOrdId with an identical payload returns the original order (duplicate: true) instead of placing a second one; reusing it with a different payload rejects with code 2009. THE VALUES IN THE EXAMPLES ON THIS PAGE ARE PLACEHOLDERS: change the reference before every send, or the second send will not do what it looks like it does. The KX- prefix is reserved for venue-generated references (liquidation and ADL closes) and is rejected with code 2020. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced (the check reads the first and the last character): references are compared character for character, and one that differs from another only by surrounding whitespace is never what a sender means." },
          "clientUid": { "type": "string", "maxLength": 64, "example": "CLIENT-A",
            "description": "Opaque end-client identifier. No PII rides an order: the venue never needs client identities to trade. Where the venue reports your transactions under MiFIR (members that are not MiFID II investment firms), the identification data behind a clientUid is submitted separately via PUT /v1/clients/{clientUid}/identity, decoupled from order entry. IDENTIFIERS ARE PERMANENT AND THE TABLE IS SHARED: the venue-wide end-client table caps at 1,048,576 distinct identifiers and is never pruned (each entry carries lifetime realized PnL and funding), so minting a fresh clientUid per session or per order consumes shared capacity permanently and ends in 2029. clientUid is the ultimate client's STABLE reference; clOrdId is the per-message one. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced (the check reads the first and the last character): references are compared character for character, and one that differs from another only by surrounding whitespace is never what a sender means." },
          "leverage": { "type": "integer", "format": "int64", "example": 10,
            "description": "Optional ASSERTION, never a control: the whole-number leverage you believe applies (initial margin = 1/leverage). Validated against YOUR account's effective margin (instrument tier times your imMultiplier, see GET /v1/account) and rejected with 2018 on mismatch, then echoed on the ack. An assertion can only ever hold on an instrument that runs ONE open-ended risk tier, which is exactly the instrument that publishes leverageMode FIXED and a non-null maxLeverage on GET /v1/instruments. WITH A TIERED INSTRUMENT THE EFFECTIVE LEVERAGE IS SIZE DEPENDENT, SO NO WHOLE NUMBER CAN BE TRUE AND EVERY VALUE REJECTS WITH 2018. Every instrument listed today is TIERED. Send this field only after reading leverageMode from GET /v1/instruments; leaving it out is always safe and never changes how the order is margined." },
          "quoteCcy": { "type": "string", "example": "USD",
            "description": "Optional ASSERTION: the quote currency you believe you are trading in. Case-insensitive match against the instrument; mismatch rejects with 2018; echoed on the ack. Every instrument listed today is quoted in USD, so this assertion holds venue-wide." },
          "trigger": { "$ref": "#/components/schemas/Trigger",
            "description": "Conditional orders only. REQUIRED on the four conditional types (STOP_MARKET, STOP_LIMIT, TAKE_PROFIT_MARKET, TAKE_PROFIT_LIMIT) and REJECTED WITH 2013 on a plain LIMIT or MARKET: a trigger block does not convert an order type, the type field selects it." },
          "reg": { "$ref": "#/components/schemas/RegFields",
            "description": "Regulatory order fields. Optional until your member has registered Authorised Users, mandatory afterwards; see the RegFields schema." }
        }
      },
      "Trigger": {
        "type": "object",
        "description": "Arming terms for a conditional order. The trigger price is NOT band-checked against the mark (an untriggered order is not a quote), but the working price it becomes on arming is: for the *_LIMIT types that is limitPrice, which is also what the minNotional floor and the per-order cap are measured against.",
        "properties": {
          "source": { "type": "string", "enum": ["LAST", "MARK", "INDEX"], "example": "MARK" },
          "price": { "type": "string", "example": "72000", "description": "Per base unit, on the tickSize grid." },
          "direction": { "type": "string", "enum": ["AT_OR_ABOVE", "AT_OR_BELOW"], "example": "AT_OR_ABOVE" },
          "limitPrice": { "type": "string", "example": "72200", "description": "Required for the *_LIMIT types; the price the order works at once armed." }
        }
      },
      "RegFields": {
        "type": "object",
        "description": "Regulatory order fields (RTS 24/22), recorded verbatim by the venue. traderId is the venue-issued Trader ID of the Authorised User entering the order; it is REQUIRED (else code 2021) once the member has registered Authorised Users. Until then the block is optional and whatever you send is recorded on the regulatory record as sent, so do not send placeholder identifiers: the example values below are shape illustrations, not values to submit.",
        "properties": {
          "traderId": { "type": "string", "example": "TR-12-9F3A21BC",
            "description": "The Trader ID of the Authorised User entering the order. Since 2.36.0 a traderId, investmentDecisionId or executionDecisionId that begins or ends with whitespace is rejected with code 2013: all three are matched exactly against your Trader ID identity records." },
          "tradingCapacity": { "type": "string", "enum": ["DEAL", "MTCH", "AOTC"], "example": "MTCH",
            "description": "VENUE trading capacity of this order, spelled in the MiFIR vocabulary but NOT MiFIR field 29: it declares the legal name of execution under the venue's semantics, and your RTS 22 report label derives from your configured per-member mapping, never the other way around. DEAL = dealing on own account. MTCH = execution in your OWN NAME for a client account, INCLUDING commission business (Finanzkommissionsgeschaeft), regardless of how your home regime labels it in transaction reports; a commission broker tags MTCH and the venue configures its MTCH-to-AOTC report mapping at onboarding. AOTC = agency in the name of the identified client. Prudential bucketing keys on these venue semantics (own-name execution accrues to dealing on own account, IFR Article 4(1)(33)). Recorded verbatim on the order's regulatory record. When the venue has activated capacity enforcement for your member (staged per member: off, warn, enforce), an ENFORCE-stage violation rejects with 2033: the field becomes required here, on RFQ creation and on RFQ quotes, the value must be one of the three codes exactly and permitted by your licensing profile, DEAL requires clientUid absent or your house reference, and MTCH and AOTC require a real end-client clientUid." },
          "clientIdType": { "type": "string", "enum": ["LEI", "NATIONAL_ID", "INTERNAL"], "example": "LEI" },
          "clientId": { "type": "string", "example": "529900T8BM49AURSDO55" },
          "investmentDecisionId": { "type": "string", "example": "ALGO-7" },
          "executionDecisionId": { "type": "string", "example": "TRADER-3" },
          "dea": { "type": "boolean", "example": false },
          "liquidityProvision": { "type": "boolean", "example": false },
          "riskReducing": { "type": "boolean", "nullable": true, "description": "RTS 22 field 64: the transaction objectively reduces risk on a commodity derivative; absent = false; only meaningful on commodity-derivative markets; recorded verbatim on the regulatory record and counted toward the 512 byte reg ceiling; venue tag 9029 on FIX (2.35.0)." }
        }
      },
      "AmendOrderRequest": {
        "type": "object",
        "description": "Both fields are optional and independent: send price alone to reprice, qty alone to resize, or both. Whatever you omit is left as it stands.",
        "properties": {
          "price": { "type": "string", "example": "68500", "description": "Per base unit, on the tickSize grid, and inside the instrument's price band (2003)." },
          "qty": { "type": "string", "example": "0.002", "description": "Decimal base units on the qtyStep grid; the FULL amended quantity must clear minNotional (2028)." }
        }
      },
      "BatchPlaceRequest": {
        "type": "object",
        "required": ["orders"],
        "properties": {
          "orders": {
            "type": "array", "minItems": 1, "maxItems": 50,
            "items": { "$ref": "#/components/schemas/PlaceOrderRequest" },
            "description": "1 to 50 COMPLETE, INDEPENDENT orders. Every entry carries its own clOrdId and clientUid and passes exactly the validation a single POST /v1/orders passes. Entries reach the engine in array order; results return in array order."
          }
        }
      },
      "MarginPreviewRequest": {
        "type": "object",
        "properties": {
          "orders": { "type": "array", "maxItems": 50, "items": { "$ref": "#/components/schemas/PlaceOrderRequest" },
            "description": "1 to 50 hypothetical orders, priced TOGETHER as one basket. Every entry is validated exactly as order entry validates it, so a malformed entry anywhere in the array fails the whole request. Perpetual entries participate in order margin jointly, with the same one-sided max(buy, sell) netting per instrument that resting orders receive; spot entries have their prefunding needs summed per currency. More than 50 entries reject with 2002." }
        }
      },
      "MarketSegmentsRequest": {
        "type": "object",
        "description": "A COMPLETE REPLACEMENT of your counterparty acceptance configuration, not a patch. Read GET /v1/market-segments first and send back what you want to end up with, including the version you just read. 2.29.0: with ?symbol= on the PUT the same body replaces your PER-MARKET layer on that market (its own version, read with GET /v1/market-segments?symbol=), a narrowing of the account configuration there: on that market you match a counterparty only when the account configuration of both sides AND the market layers of both sides admit each other.",
        "properties": {
          "restricted": { "type": "boolean", "example": false,
            "description": "false (the venue default) means you accept every member as a counterparty. true means you accept ONLY the member codes in allow, which narrows what you can match with on the book and which RFQs you see, so sending it changes your trading, not just your configuration." },
          "allow": { "type": "array", "items": { "type": "string" }, "example": [],
            "description": "Member codes, meaningful only when restricted is true. An unknown code rejects the whole request with 4002." },
          "version": { "type": "integer", "example": 0,
            "description": "Optimistic concurrency, and it is NOT optional in effect: an omitted version reads as 0. Send the version GET /v1/market-segments just returned; anything else rejects with 4001 and changes nothing. 0 is the version of a member that has never configured Market Segments, and every successful write increments it, so a value copied from an example is right at most once." }
        }
      },
      "Order": {
        "type": "object",
        "description": "An order as the venue reports it: on the place ack (with any executions produced while matching), on amend and cancel responses, on order reads and on private WebSocket order frames. All prices and quantities are decimal strings.",
        "properties": {
          "orderId": { "type": "integer", "format": "int64", "example": 501277,
            "description": "Venue order id: the handle for GET, PUT and DELETE /v1/orders/{orderId}." },
          "clOrdId": { "type": "string", "example": "my-order-1",
            "description": "Your reference, echoed on every response and notification for this order. Venue-generated closes use the reserved KX- namespace." },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY" },
          "type": { "type": "string", "enum": ["LIMIT", "MARKET", "STOP_MARKET", "STOP_LIMIT", "TAKE_PROFIT_MARKET", "TAKE_PROFIT_LIMIT"], "example": "LIMIT" },
          "tif": { "type": "string", "enum": ["GTC", "IOC", "FOK", "POST_ONLY", "GTD"], "example": "GTC" },
          "price": { "type": "string", "nullable": true, "example": "69000",
            "description": "Per base unit. Null on market orders and on conditionals that have not armed (an unarmed conditional's working price is trigger.limitPrice)." },
          "qty": { "type": "string", "example": "0.001", "description": "Decimal base units." },
          "remainingQty": { "type": "string", "example": "0.001" },
          "reduceOnly": { "type": "boolean", "example": false },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true,
            "description": "Echo of the hedge-mode position side the order was placed with. OMITTED, never null, on netting orders, so every pre-hedge payload stays byte-identical." },
          "trigger": { "$ref": "#/components/schemas/Trigger", "nullable": true, "description": "Conditional orders only." },
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "status": { "type": "string", "enum": ["NEW", "PENDING_TRIGGER", "PARTIALLY_FILLED", "FILLED", "CANCELED", "EXPIRED", "REJECTED"], "example": "NEW",
            "description": "Order state. NEW is a working order with nothing filled; PARTIALLY_FILLED a working order with fills, whether it was part filled on entry or its resting remainder was later consumed by an aggressor (since 2.26.8 the live reads GET /v1/orders/open, GET /v1/orders/{orderId}, WS get.openOrders / get.order and the FIX 150=I restatement report the latter case as PARTIALLY_FILLED; before, they reported NEW with remainingQty below qty, and on the sandbox they still do until venue operations announce the activation of that rule). Event payloads (order channel, FIX drop copy, history) always derived it from the fill." },
          "cancelReason": { "type": "string", "nullable": true, "description": "CANCELED orders only. See the cancelReason table in the complete code reference; POSITION_SIZE_LIMIT is venue-initiated and not reachable at any tradable size." },
          "rejectCode": { "type": "integer", "nullable": true,
            "description": "REJECTED orders: the registry code the engine rejected with (2007 no liquidity, 2011 position cap, and so on). Also 5005 on an order a contained command left standing (the place ack and, since 2.38.0, the batch amendment and cancellation rows): the command took effect before a venue-side fault, so reconcile and never resend it unchanged." },
          "duplicate": { "type": "boolean", "nullable": true,
            "description": "true when a reused clOrdId with an identical payload returned the original order instead of placing a second one; omitted otherwise." },
          "queueQtyAhead": { "type": "string", "nullable": true, "example": "0.5",
            "description": "Queue position at rest: the quantity resting ahead of this order at its price level (FIFO priority), PRESENT only on the place ack and ORDER_ACCEPTED frame of a placement that RESTED the order. \"0\" means front of the level, so presence is the signal that the order rested. OMITTED, never null, wherever no queue position exists: full fills, IOC/FOK/market remainders, conditionals accepted PENDING_TRIGGER, rejects, amend responses and history reads. A snapshot at the moment of rest, measured after any reduce-only trim the same placement caused, and immediately stale: the venue never updates it." },
          "queueOrdersAhead": { "type": "integer", "nullable": true, "example": 3,
            "description": "Queue position at rest: the number of orders ahead at that level, beside queueQtyAhead and under the same presence rule (both fields appear together or not at all; 0 means front of the queue)." },
          "executions": { "type": "array", "nullable": true, "items": { "$ref": "#/components/schemas/Execution" },
            "description": "Place acks only: the executions produced while the order matched. Omitted when there were none." },
          "acceptedTs": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Unix ms, a different instant per surface (described in 2.40.0, Member API revision 3.83 section 6; nothing changed). On every order frame, every stream row and every answer rendered from an order event (the DELETE /v1/orders/{orderId} answer, a cancellation batch row, a PUT answer whose amendment ended the order, a read of an order already terminal) it is the time of the event reported: the acceptance, the amendment (a venue reduce-only trim included), the trigger, the completing fill, the cancel, the expiry or the rejection. On the open-order reads (GET /v1/orders/open, GET /v1/orders/{orderId} and the PUT answer while the order is open) it is the placement time, moved to an amendment's time only by an amendment of a working order that changes the price or increases the quantity (cancel and new)." },
          "leverage": { "type": "integer", "format": "int64", "nullable": true,
            "description": "Echo of a validated order-level leverage assertion; present only when asserted." },
          "quoteCcy": { "type": "string", "nullable": true,
            "description": "Echo of a validated quote-currency assertion; present only when asserted." }
        }
      },
      "Execution": {
        "type": "object",
        "description": "One fill, seen from your side. Venue-initiated closes carry refSource VENUE and a venue-generated reference (KX-LQ-{orderId} on a liquidation slice, KX-ADL-{tradeId} on an ADL close).",
        "properties": {
          "tradeId": { "type": "integer", "format": "int64", "example": 990312 },
          "orderId": { "type": "integer", "format": "int64", "example": 501277 },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY", "description": "Your side of the fill." },
          "price": { "type": "string", "example": "69000" },
          "qty": { "type": "string", "example": "0.001" },
          "fee": { "type": "string", "example": "0.0345", "description": "Settlement currency, except on a yield contract take (flags SWAP, 2.26.0) where the fee is booked in the market's asset. Negative is a rebate." },
          "role": { "type": "string", "enum": ["MAKER", "TAKER"], "example": "TAKER" },
          "flags": { "type": "string", "enum": ["NORMAL", "LIQUIDATION", "ADL", "RFQ", "BARRIER_CLOSE", "REVERSAL", "SWAP", "AUCTION"], "example": "NORMAL", "description": "BARRIER_CLOSE (2.23.0): the trade an accepted barrier close request prints; it is an RFQ execution that closes a contract, so the more specific label wins. SWAP (2.26.0): a yield contract take (a take on a SWAP market); it ranks above RFQ and BARRIER_CLOSE, price is the offer's rate in basis points, qty the taken size, fee in the market's asset. The vocabulary is additive: treat unknown values as opaque." },
          "positionEffect": { "type": "string", "enum": ["OPEN", "INCREASE", "PARTIAL_CLOSE", "CLOSE", "FLIP"], "nullable": true, "example": "OPEN",
            "description": "2.39.0, documented for the first time (served since Member API 3.32): what the fill did to YOUR end-client sub-position in its bucket. OPEN from flat, INCREASE away from zero, PARTIAL_CLOSE toward zero without reaching it, CLOSE to flat, FLIP through zero into the opposite direction. A liquidation or ADL execution always reduces (an ADL tear-up reads PARTIAL_CLOSE); a REVERSAL undoes the original trade and can carry OPEN or INCREASE: always read the stamped value. Carried by GET /v1/executions, the WebSocket execution frame, the event stream and FIX tag 9019. OMITTED, never null, on a fill recorded before Member API 3.32, on a fill that left the sub-position unchanged (since Member API 3.81 also on GET /v1/executions, which served an empty string there before), and on the executions of a placement acknowledgement." },
          "clOrdId": { "type": "string", "example": "my-order-1" },
          "refSource": { "type": "string", "enum": ["MEMBER", "VENUE"], "example": "MEMBER" },
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "uti": { "type": "string", "nullable": true, "example": "2138005EFA978Y43G944000000990312", "description": "2.35.0: EMIR unique transaction identifier of the venue leg: the venue LEI plus the trade id zero-padded to 12, PERP and BARRIER only, absent until the venue LEI is configured. Derived at read time from the durable trade id, so the same fill carries the same value on every surface and on every later read." },
          "ts": { "type": "integer", "format": "int64", "example": 1785470168892 }
        }
      },
      "OrderHistoryRow": {
        "type": "object",
        "description": "One closed or rejected order as GET /v1/orders/history reports it. Rejections that never reached the book carry orderId 0 and a rejectCode; correlate those by clOrdId or clientUid.",
        "properties": {
          "orderId": { "type": "integer", "format": "int64", "example": 501277,
            "description": "Venue order id; 0 on a rejection that never reached the book." },
          "clOrdId": { "type": "string", "example": "my-order-1" },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY" },
          "price": { "type": "string", "nullable": true, "example": "69000" },
          "qty": { "type": "string", "example": "0.001" },
          "remainingQty": { "type": "string", "example": "0" },
          "status": { "type": "string", "enum": ["FILLED", "CANCELED", "EXPIRED", "REJECTED"], "example": "FILLED",
            "description": "Terminal states only: working orders live on GET /v1/orders/open." },
          "cancelReason": { "type": "string", "nullable": true,
            "description": "CANCELED orders only. See the cancelReason table in the complete code reference." },
          "rejectCode": { "type": "integer", "nullable": true,
            "description": "REJECTED orders only: the registry code the order was rejected with." },
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true,
            "description": "Hedge mode: the position side the order was placed with. OMITTED, never null, on netting orders, exactly like the live order surfaces." },
          "acceptedTs": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Unix ms (described in 2.40.0, Member API revision 3.83 section 6; nothing changed): on a FILLED, CANCELED or EXPIRED row the first acceptance of the order, on a REJECTED row the time of the rejection, also for an order that rested and was rejected when an amendment repriced it to cross. The from and to parameters bound this field." },
          "closedTs": { "type": "integer", "format": "int64", "example": 1785470169990, "description": "Unix ms of the terminal event (the completing fill, the cancel, the expiry or the rejection; on a REJECTED row equal to acceptedTs)." }
        }
      },
      "Lot": {
        "type": "object",
        "description": "One OPEN lot of an end client's sub-position: the surviving part of one opening fill, folded on demand from the fill history. Lots are a display convention over fills: the engine keeps no lots, margin and liquidation and the venue's booked realized PnL remain average-cost per sub-position. The open lots' qty sums exactly to the bucket's net quantity once asOfSeq has passed your last fill. Their unrealizedPnl is measured from each lot's own entry price, the sub-position's unrealizedPnl on GET /v1/positions/end-clients from its average cost, so the two sums agree only until a partial close leaves lots at different entry prices; from then on they differ by exactly the realized PnL the lot attribution has taken over the venue's booked figure since the bucket was last flat (Member API section 6e; before 2.39.0 this description said the sum was exact).",
        "properties": {
          "lotId": { "type": "integer", "format": "int64", "example": 990312,
            "description": "The tradeId of the opening fill: stable, unique, and correlates with your executions." },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true,
            "description": "The hedge-mode bucket the lot belongs to. OMITTED, never null, on netting-bucket lots, exactly like every other order surface." },
          "direction": { "type": "string", "enum": ["LONG", "SHORT"], "example": "LONG",
            "description": "The lot's own direction. In the netting bucket lots flip through zero, so a netting lot can be SHORT." },
          "entryPrice": { "type": "string", "example": "68000", "description": "The opening fill's price." },
          "qty": { "type": "string", "example": "0.002", "description": "REMAINING quantity after partial consumption, decimal base units." },
          "unrealizedPnl": { "type": "string", "nullable": true, "example": "2",
            "description": "Entry to the current mark on the remaining quantity; OMITTED while the market has no mark price yet." },
          "accFunding": { "type": "string", "example": "-1.4",
            "description": "Financing this lot has been charged since it opened, in the response's settleCcy, signed from the client's side (negative paid). An ATTRIBUTION of the charge the venue booked on the sub-position net, exact per anchor and summing to that charge to the micro; it is not itself a booked figure. Charged on the quantity held AT each anchor, so a partially closed lot keeps what it incurred while it was larger. 0 on spot, which never funds." },
          "fundingIntervals": { "type": "integer", "example": 7,
            "description": "How many funding settlements this lot has been open across, counting anchors that settled at a zero rate." },
          "openedTs": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Unix ms of the opening fill." },
          "openClOrdId": { "type": "string", "nullable": true, "example": "my-open-17",
            "description": "YOUR OWN reference on the fill that opened this lot: the clOrdId you sent on the opening order, so a lot is addressable by your client-generated id without a mapping table. Transport independent, so a FIX order's ClOrdID(11) lands here exactly as a REST clOrdId does; this is what venue tag 9028 (TargetOpenClOrdID) resolves against. OMITTED, not null, where the opening leg has no order of yours to name (no clOrdId sent, an RFQ acceptance leg, a venue-initiated open). NOT a unique key: one order filling in several prints opens one lot per fill and every one of them carries that order's reference, and clOrdId uniqueness is only a 24 hour window." },
          "openOrderId": { "type": "integer", "format": "int64", "nullable": true, "example": 774120,
            "description": "The venue orderId of the order whose fill opened this lot. OMITTED, not null, on a venue-generated opening leg, which has no order row." }
        }
      },
      "LotClosure": {
        "type": "object",
        "description": "One close attribution: which lot a closing fill consumed, and how much. Produced by the same fold that builds GET /v1/lots but WITHOUT its clamp to the live sub-position, so a close the fold cannot attribute (a liquidation on an RFQ-mode market) trims the lot from GET /v1/lots and has no row here (before 2.39.0 this description said the two views could never disagree).",
        "properties": {
          "closeTradeId": { "type": "integer", "format": "int64", "example": 991402,
            "description": "The tradeId of the closing fill, so a row correlates with your executions." },
          "lotId": { "type": "integer", "format": "int64", "example": 990312,
            "description": "The lot consumed, as GET /v1/lots reported it while it was open." },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true,
            "description": "The hedge bucket. OMITTED, never null, on netting-bucket rows." },
          "qty": { "type": "string", "example": "0.002",
            "description": "How much of the lot THIS row consumed, decimal base units; not the closing fill's total, which can span several lots." },
          "openPrice": { "type": "string", "example": "68000", "description": "The consumed lot's entry price." },
          "closePrice": { "type": "string", "example": "69100", "description": "The closing fill's price." },
          "realizedPnl": { "type": "string", "example": "2.2",
            "description": "(closePrice - openPrice) x the LOT's direction x qty, in the response's settleCcy. FIFO attribution and presentational: the venue books realized PnL average-cost per sub-position, and only that booked figure settles with you." },
          "openClOrdId": { "type": "string", "nullable": true, "example": "my-open-17",
            "description": "Your reference on the order that opened the consumed lot, the same value GET /v1/lots carries. OMITTED where the opening leg had none." },
          "closeClOrdId": { "type": "string", "nullable": true, "example": "my-close-31",
            "description": "Your reference on the CLOSING order. A venue-initiated close carries no reference of yours, so the venue derives one in its reserved namespace: KX-ADL-{closeTradeId} for an auto-deleveraging tear-up, KX-LQ-{orderId} for a liquidation close. KX- is refused on order entry with 2020, so a derived reference can never collide with one of yours: do not match it against your own order table." },
          "flags": { "type": "string", "example": "NORMAL",
            "description": "The closing fill's trade flags: NORMAL, LIQUIDATION, ADL or REVERSAL on the markets that have lots. The set is open, parse defensively." },
          "unsolicited": { "type": "boolean", "example": false,
            "description": "true exactly when flags is LIQUIDATION, ADL or REVERSAL: the venue closed the lot, you did not." },
          "ts": { "type": "integer", "format": "int64", "example": 1785471002480, "description": "Unix ms of the closing fill." }
        }
      },
      "CloseLotRequest": {
        "type": "object",
        "required": ["clientUid", "symbol"],
        "description": "Close one open lot: the venue submits a MARKET IOC order on the opposite side of the lot for its remaining quantity, tagged with the lot's hedge bucket, and records an assignment so the fold consumes THAT lot first instead of the FIFO-oldest. STRICT like order entry: an unknown JSON field rejects with 2017.",
        "properties": {
          "clientUid": { "type": "string", "maxLength": 64, "example": "CLIENT-A" },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "reduceOnly": { "type": "boolean", "example": false,
            "description": "LEAVE THIS FALSE for an ordinary client close. The default is false DELIBERATELY: the reduce-only budget is judged against your MEMBER NET position and never against the client's sub-position, so a client-level close while the member aggregate leans the other way is refused 2008 even though that client genuinely holds the lot, and a perfectly netted member book refuses every reduce-only order on the instrument. Without the flag the close is a plain order under normal margin admission, which is what a per-client close should be. Send true ONLY when you are deliberately reducing MEMBER exposure and the member position covers it, and you want the venue-enforced guarantee that the order can only ever reduce. See the reduceOnly field on PlaceOrderRequest." },
          "clOrdId": { "type": "string", "maxLength": 36, "example": "close-lot-1",
            "description": "Your optional reference for the close order, usual rules: unique per member per 24 h, the KX- prefix reserved (2020)." },
          "reg": { "$ref": "#/components/schemas/RegFields",
            "description": "Optional regulatory fields for the close ORDER this endpoint submits, same shape and rules as on POST /v1/orders. Added at 2.13.0: a member under ENFORCE-stage capacity enforcement needs a carrier here or every lot close would reject 2033. A lot close is client-attributable flow, so the natural tradingCapacity is AOTC (or MTCH under a matched principal model)." }
        }
      },
      "BatchEntryError": {
        "type": "object",
        "required": ["code", "msg"],
        "description": "A placement batch entry that did not produce an order: refused by the gateway (strict fields and wrong-typed values 2017, reserved KX- namespace 2020, grid misalignment 2002, and so on), the matching engine's 2009 (a duplicate clOrdId with a different payload), an entry the venue did not accept (5001; after an entry the venue's intake refused as it was submitted, every later entry answers 5001 \"not submitted\"; on a clustered deployment the replicated intake can refuse an entry after the later ones were submitted, which may then take effect: read every row) or, since 2.38.0, whose outcome it could not confirm (5000: reconcile by clOrdId and resend only with the SAME clOrdId). A row carrying code is a failure row. The entry's clOrdId is echoed even when the entry did not deserialize.",
        "properties": {
          "code": { "type": "integer", "example": 2017 },
          "msg": { "type": "string", "example": "unknown field" },
          "clOrdId": { "type": "string", "example": "my-batch-1a" }
        }
      },
      "BatchAmendRequest": {
        "type": "object",
        "required": ["amends"],
        "additionalProperties": false,
        "description": "2.38.0: POST /v1/orders/batch/amend. The body carries exactly one member, amends; any other member (an atomic flag, or the orders member of a placement body) answers 2002 for the whole message.",
        "properties": {
          "amends": {
            "type": "array", "minItems": 1, "maxItems": 50,
            "items": { "$ref": "#/components/schemas/BatchAmendEntry" },
            "description": "1 to 50 amendments of your own orders. Each entry the venue submits reaches the matching engine exactly as PUT /v1/orders/{orderId}, in array order; results return in array order. An order named by two entries: the first runs, every later one answers 2013."
          }
        }
      },
      "BatchAmendEntry": {
        "type": "object",
        "required": ["orderId"],
        "additionalProperties": false,
        "description": "One amendment. STRICT and parsed with case-sensitive member names: an unknown member (a clOrdId, Qty for qty) answers 2017 naming it, and a value of the wrong JSON type answers 2017 \"malformed request body\". Neither price nor qty is the single amendment's accepted no-op (amended in place, charged and counted).",
        "properties": {
          "orderId": { "type": "integer", "format": "int64", "minimum": 1, "example": 887731,
            "description": "The venue order id of one of your own orders, from GET /v1/orders/open or a place ack. Absent or below 1 answers 2013; an order that is not found, not yours or terminal answers 2014 and nothing is submitted for it." },
          "price": { "type": "string", "example": "64990.5", "description": "The new price, a decimal string on the order's tick grid, exactly as on PUT /v1/orders/{orderId}. Omit to keep the price." },
          "qty": { "type": "string", "example": "0.15", "description": "The new TOTAL quantity, fills included, a decimal string on the order's qtyStep grid, exactly as on PUT /v1/orders/{orderId}. Omit to keep the quantity." }
        }
      },
      "BatchCancelRequest": {
        "type": "object",
        "required": ["cancels"],
        "additionalProperties": false,
        "description": "2.38.0: POST /v1/orders/batch/cancel. The body carries exactly one member, cancels; any other member answers 2002 for the whole message.",
        "properties": {
          "cancels": {
            "type": "array", "minItems": 1, "maxItems": 50,
            "items": { "$ref": "#/components/schemas/BatchCancelEntry" },
            "description": "1 to 50 cancellations of your own orders. The venue looks every entry up first; an entry naming no open order of yours answers 2014 and nothing is submitted for it, every other entry reaches the matching engine exactly as DELETE /v1/orders/{orderId}, in array order."
          }
        }
      },
      "BatchCancelEntry": {
        "type": "object",
        "additionalProperties": false,
        "description": "One cancellation, naming the order by orderId OR by clOrdId, exactly one (both or neither answers 2013). STRICT and parsed with case-sensitive member names, like BatchAmendEntry.",
        "oneOf": [
          { "required": ["orderId"] },
          { "required": ["clOrdId"] }
        ],
        "properties": {
          "orderId": { "type": "integer", "format": "int64", "minimum": 1, "example": 887734,
            "description": "The venue order id of one of your open orders." },
          "clOrdId": { "type": "string", "minLength": 1, "example": "q-ask-3",
            "description": "Your reference on an open order of yours, compared character for character and never refused for padding (a cancel by reference is a lookup)." }
        }
      },
      "BatchTargetError": {
        "type": "object",
        "required": ["code", "msg"],
        "description": "2.38.0: the failure row of a batch amendment or cancellation entry. A row carrying code is a failure row; any other row is the Order. orderId is echoed only when the entry carried a JSON integer of at least 1 (and on a cancellation entry by reference, the order the reference resolved to); clOrdId only when the entry carried a JSON string; otherwise the member is omitted. The codes: 2017, 2013 (including an order already named by an earlier entry of the batch), 2014, 1004 (an amendment on a market the order-to-trade regime blocks), 2049, 2002, every refusal of the single amend or cancel by the matching engine, 5005 when a contained fault left nothing in effect, 5001 (not accepted, or not submitted after an earlier entry the intake refused as it was submitted; on a clustered deployment the replicated intake can refuse an entry after the later ones were submitted, which may then take effect: read every row) and 5000 (outcome unknown: read the order back on the leader before sending it again).",
        "properties": {
          "code": { "type": "integer", "example": 2014 },
          "msg": { "type": "string", "example": "order not found" },
          "orderId": { "type": "integer", "format": "int64", "example": 887732 },
          "clOrdId": { "type": "string", "example": "q-ask-3" }
        }
      },
      "Account": {
        "type": "object",
        "description": "One margin account row per settlement currency. All amounts are decimal strings in that currency.",
        "properties": {
          "ccy": { "type": "string", "example": "USD" },
          "balance": { "type": "string", "example": "1000000" },
          "equity": { "type": "string", "example": "1001200", "description": "balance plus unrealized P&L." },
          "unrealizedPnl": { "type": "string", "example": "1200" },
          "positionIM": { "type": "string", "example": "13800", "description": "Initial margin held against open positions." },
          "orderMargin": { "type": "string", "example": "690", "description": "Initial margin held against open orders." },
          "MM": { "type": "string", "example": "6900", "description": "Maintenance margin. The property name is uppercase MM on the wire." },
          "available": { "type": "string", "example": "986710", "description": "Free collateral; never reported below zero." },
          "spotReserved": { "type": "string", "example": "0",
            "description": "Cash promised to open spot orders (worst-case quote for buys), already subtracted from available." },
          "marginRatio": { "type": "string", "nullable": true, "example": "0.006891", "description": "MM divided by equity; null when equity is not positive." },
          "riskStatus": { "type": "string", "enum": ["NORMAL", "MARGINCALL", "LIQUIDATION", "DEFAULTED"], "example": "NORMAL",
            "description": "This field spells the margin-call state MARGINCALL; the venueEvents channel spells the same state MARGIN_CALL." },
          "imMultiplier": { "type": "string", "example": "1",
            "description": "Member margin profile, exact decimal string: effective initial margin = instrument tier rate times this value. The order-level leverage assertion validates against the member-effective figure." },
          "feeTier": { "type": "string", "nullable": true, "description": "Assigned fee tier name; null when the member trades at instrument default fees." },
          "makerFeeRate": { "type": "string", "nullable": true,
            "description": "Member default rate when a tier or override applies; null means per-instrument defaults (see GET /v1/instruments). Negative maker is a rebate. Not applied on SWAP markets, where every member pays the instrument rates (2.35.0, section 6h)." },
          "takerFeeRate": { "type": "string", "nullable": true, "description": "As makerFeeRate; not applied on SWAP markets (2.35.0)." },
          "stp": { "type": "string", "enum": ["CANCEL_RESTING", "CANCEL_TAKER", "CANCEL_BOTH", "REJECT_TAKER"], "example": "CANCEL_RESTING",
            "description": "2.28.0: your self-trade prevention policy, elected on PUT /v1/account/stp (section 6, Self-trade prevention)." },
          "stpScope": { "type": "string", "enum": ["END_CLIENT", "MEMBER"], "example": "END_CLIENT",
            "description": "2.28.0: END_CLIENT (only orders of the same clientUid or house account are prevented from matching), MEMBER (no same-member matching at all)." },
          "assets": { "type": "array", "items": { "$ref": "#/components/schemas/AssetBalance" },
            "description": "Base-asset holdings from spot trading; empty when none." }
        }
      },
      "AccountStpRequest": {
        "type": "object",
        "description": "2.28.0: the member's own STP election (PUT /v1/account/stp). Name one or both fields; an omitted field keeps its current value. The same-clientUid wash-trade block is non-optional under every policy. 2.29.0: with symbol the election is your PER-MARKET policy on that market (it wins over the account election there; INHERIT removes it again), read back per market on GET /v1/account/parameters markets[].stp with stpSource SELF_MARKET.",
        "properties": {
          "stp": { "type": "string", "enum": ["CANCEL_RESTING", "CANCEL_TAKER", "CANCEL_BOTH", "REJECT_TAKER", "INHERIT"], "example": "CANCEL_RESTING",
            "description": "INHERIT (2.29.0, with symbol only) removes the per-market election so the account policy applies on that market again." },
          "stpScope": { "type": "string", "enum": ["END_CLIENT", "MEMBER", "INHERIT"], "example": "END_CLIENT" },
          "symbol": { "type": "string", "nullable": true, "example": "BTC-USD-PERP", "description": "2.29.0: elect the policy for this market only. Unknown symbol: 2001." }
        }
      },
      "AssetBalance": {
        "type": "object",
        "properties": {
          "asset": { "type": "string", "example": "BTC" },
          "total": { "type": "string", "example": "0.5" },
          "reserved": { "type": "string", "example": "0.1", "description": "Units reserved by open spot sell orders." },
          "free": { "type": "string", "example": "0.4" },
          "reference": { "$ref": "#/components/schemas/AssetReference", "description": "2.35.0: present on a EUR asset row only, see AssetReference; omitted otherwise." }
        }
      },
      "AssetReference": {
        "type": "object",
        "description": "2.35.0: informational, non-binding USD equivalent of a EUR balance (total times the rate) at the ECB euro reference rate (series EXR/D.USD.EUR.SP00.A, USD per 1 EUR, four decimals as published); omitted (not null) on every other asset row, and omitted when no rate is loaded or the newest ECB date is older than the venue's staleness cutoff (five calendar days unless the venue publishes otherwise). Never a conversion: the EUR balance stays segregated and unconverted.",
        "properties": {
          "rateCcy": { "type": "string", "example": "USD", "description": "Always USD, the currency the equivalent is expressed in." },
          "rate": { "type": "string", "example": "1.0912", "description": "USD per 1 EUR as the ECB published it, up to four decimals, trailing zeros trimmed." },
          "rateDate": { "type": "string", "example": "2026-09-10", "description": "The ECB reference date, yyyy-MM-dd." },
          "source": { "type": "string", "example": "ECB", "description": "Always ECB." },
          "equivalent": { "type": "string", "example": "1091.2", "description": "total times rate, rounded half even to six decimals." },
          "label": { "type": "string", "example": "informational, non-binding, ECB reference rate", "description": "The constant label; the figure is not a balance and is never read by risk." }
        }
      },
      "Position": {
        "type": "object",
        "description": "A net position. Member-level rows omit clientUid; GET /v1/positions/end-clients rows carry it.",
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "netQty": { "type": "string", "example": "0.5", "description": "Signed decimal base units: positive long, negative short." },
          "avgEntry": { "type": "string", "example": "68000" },
          "markPrice": { "type": "string", "nullable": true, "example": "69000" },
          "unrealizedPnl": { "type": "string", "example": "500" },
          "realizedPnl": { "type": "string", "example": "120" },
          "accFunding": { "type": "string", "example": "-3.2", "description": "Lifetime funding booked against this position, in settleCcy, signed from your side: negative paid, positive received. Never resets, including across a flat." },
          "settleCcy": { "type": "string", "example": "USD", "description": "Currency unrealizedPnl, realizedPnl and accFunding are expressed in. Settlement is per instrument, so a member holding positions across markets cannot assume one currency down the list." },
          "adlQuintile": { "type": "integer", "example": 2, "description": "Auto-deleveraging queue quintile, 1 to 5 (5 = first to be auto-deleveraged): rank by unrealized profit ratio multiplied by account leverage, highest first, ties by ascending member id, losing positions below every profitable one; recomputed every 5 seconds. See GET /v1/adl/indicator." },
          "clientUid": { "type": "string", "nullable": true, "description": "End-client rows only." },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true,
            "description": "Hedge mode, end-client rows only: the LONG or SHORT sub-position bucket this row reports. OMITTED on netting rows and on member-level rows, so a client using hedge mode can have up to three rows per instrument." }
        }
      },
      "EodClientPosition": {
        "type": "object",
        "description": "2.39.0: one end-client sub-position as the venue's end-of-day snapshot recorded it (GET /v1/reconciliation/end-client-positions). A row is immutable once written; the rows of one day can stand for different instants where the anchor ran again for that day (see the route). Figures are decimal strings.",
        "properties": {
          "date": { "type": "string", "format": "date", "example": "2026-10-18", "description": "The business day the snapshot stands for, YYYY-MM-DD." },
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "positionSide": { "type": "string", "enum": ["LONG", "SHORT"], "nullable": true, "example": "LONG",
            "description": "The hedge-mode bucket of the row. OMITTED, never null, on netting rows; the CSV prints NET there." },
          "netQty": { "type": "string", "example": "0.002", "description": "Signed decimal base units: positive long, negative short." },
          "avgEntry": { "type": "string", "example": "68000.5", "description": "The sub-position's average entry price as GET /v1/positions/end-clients served it at the snapshot: a display figure cut below the price grid, not the booked cost basis." },
          "mark": { "type": "string", "nullable": true, "example": "69000", "description": "The market's mark price at the snapshot. OMITTED when the market had none." },
          "upnl": { "type": "string", "nullable": true, "example": "1.999",
            "description": "Since 2.39.0 (Member API 3.81): unrealized PnL at mark in the market's settlement currency, exact to the micro: the unrealizedPnl GET /v1/positions/end-clients reports at that mark, computed from the booked cost basis, so it can differ by micros from netQty x (mark - avgEntry). Written only where the history store's net quantity for the row equalled the matching engine's at the snapshot's instant. OMITTED otherwise, without a mark, and on every row recorded before revision 3.81 (rows are never rewritten)." }
        }
      },
      "ClientIdentityRequest": {
        "type": "object",
        "required": ["type"],
        "description": "RTS 22 Annex I Table 2 identification for one clientUid, submitted for the transaction reports the venue owes under MiFIR Article 26(5) for members that are not MiFID II investment firms. STRICT like order entry: an unknown JSON field rejects with 2017. Cross-field rules: lei on LEGAL_ENTITY only; dateOfBirth, nationalId and nationalIdType on NATURAL_PERSON only. Any validation failure rejects with 2030 and a msg naming the offending field. Never read by matching, margin or any risk path.",
        "properties": {
          "type": { "type": "string", "enum": ["NATURAL_PERSON", "LEGAL_ENTITY"], "example": "NATURAL_PERSON" },
          "countryCode": { "type": "string", "minLength": 2, "maxLength": 2, "example": "DE",
            "description": "ISO 3166-1 alpha-2, uppercase. Required for natural persons (the nationality that selects the Annex II identifier priority; for a person with more than one nationality send the one RTS 22 Article 6(3) designates: an EEA nationality over a non-EEA one, then the ISO 3166-1 alpha-2 code that sorts first, per the ESMA transaction reporting guidelines section 5.5.1); optional for legal entities." },
          "identifierPriority": { "type": "integer", "minimum": 1, "maximum": 3, "nullable": true, "example": 2,
            "description": "Optional: the Annex II priority rank the supplied national identifier holds for that country. Since revision 3.53 it defaults to the rank the RTS 22 Annex II table gives the identifier for the country and, when sent, must agree with the table (ENFORCE stage, in force on production from its first day and on the sandbox from Tuesday 2026-09-22: 2030; the sandbox WARN stage before that date stores the record and reports the contradiction in warnings)." },
          "nationalIdType": { "type": "string", "maxLength": 32, "nullable": true, "example": "PASSPORT",
            "description": "Your scheme label for the national identifier. Since revision 3.53 the label must be one the RTS 22 Annex II table designates for the country (canonical labels and their aliases per country, for example PESEL for PL, FISCAL_CODE for IT, TAX_ID for ES and PT, NATIONAL_INSURANCE for GB, PASSPORT where the country lists the passport, NATIONAL_ID as the generic alias of the country's first national number); an unknown label is refused with 2030 in the ENFORCE stage (production from its first day, sandbox from Tuesday 2026-09-22) and, in the sandbox WARN stage before that date, stored and reported in warnings. Required when nationalId is set, and only then." },
          "nationalId": { "type": "string", "maxLength": 64, "nullable": true, "example": "C01X00T47",
            "description": "The national identifier itself. Natural persons only. When absent for a natural person the venue derives the RTS 22 CONCAT code from country, date of birth and name. Since revision 3.70 the value is checked on both rollout stages: no control or formatting character, no leading or trailing whitespace, never a leading =, +, - or @ (refused with 2030; the value is filed verbatim as the position holder identifier of the venue's Art 58 report); a + or - inside the value is accepted." },
          "firstName": { "type": "string", "maxLength": 140, "nullable": true, "example": "Jürgen", "description": "Required for natural persons, 1 to 140 characters. Submit the name as held; the venue removes titles and listed surname prefixes itself when it derives the CONCAT code (ESMA transaction reporting guidelines, section 5.5.1)." },
          "surname": { "type": "string", "maxLength": 140, "nullable": true, "example": "Müller", "description": "Required for natural persons, 1 to 140 characters." },
          "dateOfBirth": { "type": "string", "nullable": true, "example": "19840217", "description": "YYYYMMDD. Required for natural persons." },
          "lei": { "type": "string", "minLength": 20, "maxLength": 20, "nullable": true, "example": "529900T8BM49AURSDO55",
            "description": "ISO 17442 LEI, checksum validated. Required for legal entities." },
          "positionHolderCategory": { "type": "string", "nullable": true, "example": "INVESTMENT_FIRM_OR_CREDIT_INSTITUTION",
            "enum": ["INVESTMENT_FIRM_OR_CREDIT_INSTITUTION", "INVESTMENT_FUND", "OTHER_FINANCIAL_INSTITUTION", "COMMERCIAL_UNDERTAKING", "EMISSIONS_OPERATOR"],
            "description": "Since revision 3.70: the MiFID II Article 58(4) position-holder category of the client, accepted on NATURAL_PERSON and LEGAL_ENTITY alike; any other value rejects with 2030. Optional, and required in practice for every clientUid that holds a position on a market flagged as a commodity derivative (the XAU, XAG, WTI and BRENT perpetuals and their knock-out markets, XAG listed on the sandbox since Member API revision 3.75): it feeds the venue's weekly Article 58(1)(a) classification of position holders; a record without it is still reported in the daily Article 58(1)(b) position report and is chased by venue operations for the weekly report. Omitted on a PUT = cleared (every PUT is a full upsert). Trading is never blocked on it." },
          "ultimateParentLei": { "type": "string", "minLength": 20, "maxLength": 20, "nullable": true, "example": "529900T8BM49AURSDO55",
            "description": "Since revision 3.70: the ISO 17442 LEI (checksum validated, else 2030) of the client's ultimate parent entity for the Article 58(1)(b) daily position report on the commodity-derivative markets; equal to lei means the client is its own parent. Optional on both client types; omitted on a PUT = cleared." }
        }
      },
      "ClientIdentity": {
        "type": "object",
        "description": "The stored identity record as served back (GET and the PUT echo): the submitted fields plus the resolved MiFIR identifier and the audit revision.",
        "properties": {
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "type": { "type": "string", "enum": ["NATURAL_PERSON", "LEGAL_ENTITY"], "example": "NATURAL_PERSON" },
          "countryCode": { "type": "string", "nullable": true, "example": "DE" },
          "identifierPriority": { "type": "integer", "nullable": true, "example": 2 },
          "nationalIdType": { "type": "string", "nullable": true, "example": "PASSPORT" },
          "nationalId": { "type": "string", "nullable": true, "example": "C01X00T47" },
          "firstName": { "type": "string", "nullable": true, "example": "Jürgen" },
          "surname": { "type": "string", "nullable": true, "example": "Müller" },
          "dateOfBirth": { "type": "string", "nullable": true, "example": "19840217" },
          "lei": { "type": "string", "nullable": true, "example": null },
          "positionHolderCategory": { "type": "string", "nullable": true, "example": null,
            "description": "Since revision 3.70: the Article 58(4) category as stored, null when the record carries none." },
          "ultimateParentLei": { "type": "string", "nullable": true, "example": null,
            "description": "Since revision 3.70: the ultimate parent LEI as stored, null when the record carries none." },
          "mifirId": { "type": "string", "example": "C01X00T47",
            "description": "The identifier the venue's transaction report will carry for this client, resolved at submission time: the LEI, the national identifier, or the derived CONCAT code (countryCode + dateOfBirth + first five letters of the first first name + first five of the surname after titles and listed surname prefixes are removed, uppercased, folded per the exact ESMA transliteration table with every character outside the table removed, #-padded to five; ESMA transaction reporting guidelines, section 5.5.1). A name that folds to no Latin letter is refused with 2030." },
          "mifirIdSource": { "type": "string", "enum": ["LEI", "NATIONAL_ID", "CONCAT"], "example": "NATIONAL_ID" },
          "mifirIdScheme": { "type": "string", "enum": ["LEI", "NIDN", "CCPT", "CONCAT", ""], "example": "CCPT",
            "description": "Since revision 3.53: the ISO 20022 scheme the identifier is reported under (RTS 22 Annex II): LEI, NIDN (national identification number), CCPT (passport) or CONCAT. Empty on records stored before the venue classified schemes, until the venue's re-validation fills it." },
          "warnings": { "type": "array", "items": { "type": "string" }, "nullable": true,
            "description": "PUT echo only, since revision 3.53: Annex II observations that did not stop the record being stored (a lower-priority identifier where a higher one exists; in the sandbox WARN stage until 2026-09-21 also a label, rank, format or CONCAT choice the table contradicts; from Tuesday 2026-09-22 on the sandbox and from the first day on production (ENFORCE) those reject with 2030 instead). Omitted when empty and on GET." },
          "revision": { "type": "integer", "example": 1,
            "description": "Monotonic per clientUid, starting at 1. Every PUT replaces the current record AND appends an immutable audit revision, so corrected reports can show what was on file when." },
          "updatedAt": { "type": "integer", "format": "int64", "example": 1785000000123, "description": "Unix ms of the last accepted PUT." }
        }
      },
      "TraderIdentityRequest": {
        "type": "object",
        "required": ["kind"],
        "description": "The identity behind a venue-issued Trader ID (RTS 22 fields 57 to 60), revision 3.53. PERSON reuses the NATURAL_PERSON rules and the Annex II per-country identifier table of ClientIdentityRequest and adds the mandatory branchCountry; ALGO carries the algorithm code and no person data. STRICT: an unknown field rejects with 2017.",
        "properties": {
          "kind": { "type": "string", "enum": ["PERSON", "ALGO"], "example": "PERSON" },
          "countryCode": { "type": "string", "minLength": 2, "maxLength": 2, "nullable": true, "example": "PL", "description": "PERSON: nationality, selects the Annex II row." },
          "identifierPriority": { "type": "integer", "minimum": 1, "maximum": 3, "nullable": true },
          "nationalIdType": { "type": "string", "maxLength": 32, "nullable": true, "example": "PESEL" },
          "nationalId": { "type": "string", "maxLength": 64, "nullable": true, "example": "44051401359" },
          "firstName": { "type": "string", "maxLength": 140, "nullable": true, "example": "Jan" },
          "surname": { "type": "string", "maxLength": 140, "nullable": true, "example": "Kowalski" },
          "dateOfBirth": { "type": "string", "nullable": true, "example": "19440514", "description": "YYYYMMDD." },
          "branchCountry": { "type": "string", "minLength": 2, "maxLength": 2, "nullable": true, "example": "CY", "description": "PERSON, required: ISO 3166-1 alpha-2 country of the branch responsible for the person (RTS 22 fields 58 and 60)." },
          "algoId": { "type": "string", "maxLength": 50, "nullable": true, "example": "MM-ENGINE-7", "description": "ALGO, required: 1 to 50 characters of A-Z a-z 0-9 . _ -." }
        }
      },
      "TraderIdentity": {
        "type": "object",
        "description": "The stored trader identity as served back (GET and the PUT echo).",
        "properties": {
          "traderId": { "type": "string", "example": "TR-7-A1B2C3D4" },
          "kind": { "type": "string", "enum": ["PERSON", "ALGO"] },
          "countryCode": { "type": "string", "nullable": true },
          "identifierPriority": { "type": "integer", "nullable": true },
          "nationalIdType": { "type": "string", "nullable": true },
          "nationalId": { "type": "string", "nullable": true },
          "firstName": { "type": "string", "nullable": true },
          "surname": { "type": "string", "nullable": true },
          "dateOfBirth": { "type": "string", "nullable": true },
          "branchCountry": { "type": "string", "nullable": true },
          "mifirId": { "type": "string", "example": "44051401359", "description": "The identifier the venue reports in fields 57 / 59 for this Trader ID: the national identifier or CONCAT of the person, or the algorithm code." },
          "mifirIdScheme": { "type": "string", "enum": ["NIDN", "CCPT", "CONCAT", "ALGO"], "example": "NIDN" },
          "revision": { "type": "integer", "example": 1 },
          "updatedAt": { "type": "integer", "format": "int64" },
          "warnings": { "type": "array", "items": { "type": "string" }, "nullable": true, "description": "PUT echo only: Annex II observations, as on the client identity PUT." }
        }
      },
      "MarginPreview": {
        "type": "object",
        "description": "What-if margin for the WHOLE basket of the preview request, computed on top of your current portfolio: the figures answer what your margin state would be with EVERY entry working at once, not what the first entry alone would cost. Nothing is placed and nothing is reserved.",
        "properties": {
          "indicative": { "type": "boolean", "example": true, "description": "Always true: a preview reads current state and is not a reservation." },
          "accepted": { "type": "boolean", "example": true, "description": "Whether the WHOLE basket would clear the admission rules placement applies: available (order margin and spot prefunding, summed per currency), the per-order size cap, the minNotional floor, the position cap and, for reduceOnly entries, the reduce-only budget, entry by entry and with the same reduce-only exemptions. Independent of array order. It does not answer halts, member or instrument status, or whether a market order would find liquidity." },
          "im": { "type": "string", "example": "1380", "description": "Initial margin requirement with the whole basket working, settlement currency of the first entry." },
          "mm": { "type": "string", "example": "690", "description": "Maintenance margin requirement, settlement currency of the first entry. Basket entries are orders, not positions, so this moves only with what you already hold." },
          "available": { "type": "string", "example": "986710", "description": "Your available collateral with the whole basket working, settlement currency of the first entry." }
        }
      },
      "MarketSegmentsConfig": {
        "type": "object",
        "description": "Your counterparty acceptance configuration as it stands. Carry version into your next PUT. 2.29.0: read with ?symbol= it is that market's PER-MARKET layer (symbol set, version 0 and restricted false while you never wrote one); read without it, markets lists every per-market layer you hold.",
        "properties": {
          "restricted": { "type": "boolean", "example": false },
          "allow": { "type": "array", "items": { "type": "string" }, "example": [], "description": "Member codes, meaningful only when restricted is true." },
          "version": { "type": "integer", "example": 3, "description": "Optimistic concurrency token: send exactly this value on your next PUT (else 4001). The account configuration and each market layer carry their own version." },
          "symbol": { "type": "string", "nullable": true, "example": "BTC-USD-PERP", "description": "2.29.0: the market this layer belongs to; absent on the account configuration." },
          "markets": { "type": "array", "nullable": true, "description": "2.29.0: on the account read, every per-market layer you hold (a market you never wrote is absent and the account configuration alone applies there).",
            "items": { "type": "object", "properties": {
              "symbol": { "type": "string", "example": "BTC-USD-PERP" },
              "restricted": { "type": "boolean" },
              "allow": { "type": "array", "items": { "type": "string" } },
              "version": { "type": "integer" } } } }
        }
      },
      "Book": {
        "type": "object",
        "description": "Depth snapshot. GET /v1/orderbook rows are [price, qty]; GET /v1/orderbook/matchable rows are [price, matchableQty, ownQty]. Every element is a decimal string; best level first.",
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "bids": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "example": [["69000", "0.5"], ["68999.5", "1.2"]] },
          "asks": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "example": [["69000.5", "0.8"]] },
          "checksum": { "type": "integer", "format": "int64", "description": "Book checksum over the rendered rows; same recipe as the WebSocket orderbook channel." },
          "seq": { "type": "integer", "format": "int64", "description": "Per-channel sequence on WebSocket frames; 0 on REST snapshots." }
        }
      },
      "Trade": {
        "type": "object",
        "properties": {
          "tradeId": { "type": "integer", "format": "int64", "example": 990312 },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "price": { "type": "string", "example": "69000" },
          "qty": { "type": "string", "example": "0.001" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY", "description": "Aggressor (taker) side." },
          "flags": { "type": "string", "enum": ["NORMAL", "LIQUIDATION", "ADL", "RFQ", "BARRIER_CLOSE", "REVERSAL", "SWAP", "AUCTION"], "example": "NORMAL", "description": "BARRIER_CLOSE (2.23.0): the trade an accepted barrier close request prints; it is an RFQ execution that closes a contract, so the more specific label wins. SWAP (2.26.0): a yield contract take (a take on a SWAP market); it ranks above RFQ and BARRIER_CLOSE, price is the offer's rate in basis points and qty the taken size. The vocabulary is additive: treat unknown values as opaque." },
          "ts": { "type": "integer", "format": "int64", "example": 1785470168892 }
        }
      },
      "Ticker": {
        "type": "object",
        "description": "Null fields have no value yet: no trade, an empty book side, or no mark or index price.",
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "lastPrice": { "type": "string", "nullable": true, "example": "69000" },
          "bestBid": { "type": "string", "nullable": true, "example": "68999.5" },
          "bestAsk": { "type": "string", "nullable": true, "example": "69000.5" },
          "markPrice": { "type": "string", "nullable": true, "example": "69000" },
          "indexPrice": { "type": "string", "nullable": true, "example": "68998" },
          "fundingRate": { "type": "string", "nullable": true, "example": "0.0001", "description": "Rate in force for the current interval on a GRID market. OMITTED (not null, never a fabricated zero) on a LOCAL_DAILY market, together with fundingRatePct, fundingRateAnnualizedPct and fundingPerUnit: there the day's rate is computed at the snapshot from the index VWAP methodology and published on the settlement frame and GET /v1/funding/history, so nothing is in force between settlements. A DIMENSIONLESS FRACTION PER INTERVAL and not a currency amount: 0.0001 is 0.01% of position notional per interval, so a 100000 USD long pays 10 USD at that rate. The currency-denominated figure is the funding PAYMENT, booked in the instrument's settlement currency and visible as accFunding on your positions and as FUNDINGPAY / FUNDINGRECEIVE on GET /v1/account/ledger. Zero on spot markets, which never fund." },
          "predictedFundingRate": { "type": "string", "nullable": true, "example": "0.00012", "description": "Running estimate for the next settlement. Always present on GRID perps (\"0\" on spot). On a LOCAL_DAILY perp it is the rate the marks recorded so far would settle at and it is OMITTED (not null) before the day's window opens." },
          "fundingRatePct": { "type": "string", "nullable": true, "example": "0.01", "description": "fundingRate as a PERCENTAGE, exactly the same number scaled by 100. Published so the fraction cannot be misread as a percentage or as an amount. Omitted whenever fundingRate is (LOCAL_DAILY)." },
          "predictedFundingRatePct": { "type": "string", "nullable": true, "example": "0.012", "description": "Omitted whenever predictedFundingRate is." },
          "fundingRateAnnualizedPct": { "type": "string", "nullable": true, "example": "10.95", "description": "fundingRate annualised to a percentage: rate x (365 days / fundingIntervalHours) x 100, simple, no compounding. A venue comparison figure. OMITTED (not null, and never 0) on a market with no funding grid, which is every spot market, because a fabricated zero would read as a market that costs nothing to hold." },
          "nextFundingTs": { "type": "integer", "format": "int64", "example": 1785484800000 },
          "openInterest": { "type": "string", "example": "125.5", "description": "Base units." },
          "volume24h": { "type": "string", "example": "3120.8", "description": "Base units traded in the last 24 hours." }
        }
      },
      "UnwindEpisode": {
        "type": "object",
        "description": "A liquidation or auto-deleveraging episode you were part of. As defaulter you see the full episode; as counterparty you see your own allocations only, with the monetary fields zeroed.",
        "properties": {
          "episodeId": { "type": "integer", "format": "int64", "example": 12 },
          "role": { "type": "string", "enum": ["DEFAULTER", "COUNTERPARTY"], "example": "COUNTERPARTY" },
          "trigger": { "type": "string", "enum": ["MARGIN_BREACH", "ADMIN_FORCED"], "example": "MARGIN_BREACH" },
          "status": { "type": "string", "enum": ["OPEN", "CLOSED"], "example": "CLOSED" },
          "canceledOrderIds": { "type": "array", "items": { "type": "integer", "format": "int64" }, "description": "Defaulter view only; empty otherwise." },
          "tradeIds": { "type": "array", "items": { "type": "integer", "format": "int64" }, "description": "Defaulter view only; empty otherwise." },
          "adlAllocations": { "type": "array", "items": { "$ref": "#/components/schemas/AdlAllocation" } },
          "insuranceFundDelta": { "type": "string", "example": "0", "description": "Settlement currency; defaulter view only, \"0\" otherwise." },
          "residualLoss": { "type": "string", "example": "0", "description": "Settlement currency; defaulter view only, \"0\" otherwise." }
        }
      },
      "AdlAllocation": {
        "type": "object",
        "properties": {
          "counterpartyClientUid": { "type": "string", "nullable": true,
            "description": "Counterparty view: your own end-client tag on the deleveraged position. Null on the defaulter's view." },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "qty": { "type": "string", "example": "0.05" },
          "price": { "type": "string", "example": "69000" }
        }
      },
      "AdlEventRow": {
        "type": "object",
        "description": "One auto-deleveraging allocation recorded for you (GET /v1/adl/events, 2.35.0). side is your relation to the episode, role the row's attribution; on the defaulter's own per-client rows both read DEFAULTER.",
        "properties": {
          "tradeId": { "type": "integer", "format": "int64", "example": 88301, "description": "The ADL trade this allocation belongs to (the same tradeId on every slice of one tear-up; several rows per trade are normal)." },
          "episodeId": { "type": "integer", "format": "int64", "example": 42, "description": "The unwind episode (GET /v1/unwinds)." },
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "price": { "type": "string", "example": "66120", "description": "The bankruptcy price both legs settled at, capped in extreme conditions to the nearest representable price." },
          "qty": { "type": "string", "example": "5", "description": "The allocation's quantity in base units." },
          "qtyLots": { "type": "integer", "format": "int64", "example": 5, "description": "The same quantity in raw engine lots (legacy)." },
          "side": { "type": "string", "enum": ["DEFAULTER", "COUNTERPARTY"], "example": "COUNTERPARTY", "description": "Your relation to the EPISODE: DEFAULTER on every row of an episode you were unwound in (your own per-client rows included), COUNTERPARTY on a slice taken from you." },
          "role": { "type": "string", "enum": ["DEFAULTER", "DELEVERAGED"], "example": "DELEVERAGED", "description": "The row's attribution (2.35.0): DEFAULTER, the defaulter's own per-client allocation; DELEVERAGED, the counterparty allocation. A row recorded before this revision reads DELEVERAGED (every one of them a counterparty row)." },
          "closeSide": { "type": "string", "nullable": true, "enum": ["BUY", "SELL"], "example": "SELL", "description": "The direction the venue closed the member named by the row in (2.35.0): on a DEFAULTER row the defaulter's close, on a DELEVERAGED row the counterparty's; omitted on a row recorded before this revision." },
          "positionSide": { "type": "string", "nullable": true, "enum": ["LONG", "SHORT"], "example": "LONG", "description": "The hedge bucket the allocation reduced; omitted for the netting bucket." },
          "clientUid": { "type": "string", "nullable": true, "example": "CLIENT-A", "description": "Your own end client on the allocation: present on your own rows (a deleveraged member's allocations, a defaulter's own per-client rows), omitted on the slices a defaulter sees taken from OTHER members (no end-client identifier crosses members)." },
          "ts": { "type": "integer", "format": "int64", "example": 1785000355900, "description": "Unix ms of the tear-up." }
        }
      },
      "StreamStore": {
        "type": "object",
        "description": "Projection staleness block: the store is authoritative only through contiguousThroughSeq (the watermark), never the engine head.",
        "properties": {
          "contiguousThroughSeq": { "type": "integer", "format": "int64", "example": 918273 },
          "engineSeq": { "type": "integer", "format": "int64", "example": 918290 },
          "lagSeq": { "type": "integer", "format": "int64", "example": 17, "description": "engineSeq minus contiguousThroughSeq. While REPAIRING it counts the commands from the start of the hole to the engine head, not the size of the hole, so it grows while the hole stands." },
          "status": { "type": "string", "enum": ["COMPLETE", "CATCHING_UP", "REPAIRING"], "example": "COMPLETE",
            "description": "CATCHING_UP: rows above the watermark exist but are not yet readable, poll again. REPAIRING: the store of the node that answered has a recorded hole and reads are clamped below it; keep polling and raise an operational alert. Since 2.40.0 (Member API revision 3.83, section 11.3; nothing changed) the text states what REPAIRING is: it starts at every leader change of a clustered venue, when the store falls further behind than its write buffer absorbs and when a store write fails beyond a short retry; no timeout ends it and the venue sets no maximum duration; it ends when the hole is re-folded from the venue's journal, by the new leader after a leader change and by venue operations otherwise. The block describes the node that answered." },
          "complete": { "type": "boolean", "example": true, "description": "True when this answer reached the requested upper bound with nothing left to fetch." }
        }
      },
      "StreamEvent": {
        "type": "object",
        "description": "One backfilled event-class message. data is byte-identical to the live private WebSocket frame's data for the same event.",
        "properties": {
          "channel": { "type": "string", "example": "order", "description": "order, execution, wallet, margin, adl, unwind, eligibility, funding or status." },
          "type": { "type": "string", "nullable": true, "description": "Live-frame type name where one exists; omitted otherwise." },
          "eventType": { "type": "string", "example": "ORDER_ACCEPTED" },
          "asOfSeq": { "type": "integer", "format": "int64", "example": 918273 },
          "eventIndex": { "type": "integer", "format": "int32", "minimum": 0, "maximum": 2147483647, "example": 0, "description": "Since 2.40.0 typed as it always was (Member API revision 3.83, section 11.2): a signed 32-bit integer, the 0-based position of the event among the events of one engine command, restarting at 0 for every asOfSeq; within one asOfSeq the values you receive increase but are not contiguous." },
          "leg": { "type": "integer", "example": 0 },
          "cursor": { "type": "string", "minLength": 30, "maxLength": 30, "example": "000000000000010487100000000040",
            "description": "30-character fixed-width numeric cursor; ordinal string comparison equals engine order." },
          "data": { "description": "The event payload, channel-specific; identical to the live frame's data." }
        }
      },
      "MarginCall": {
        "type": "object",
        "description": "One MARGIN_CALL notice with the account figures at the time of the call.",
        "properties": {
          "seq": { "type": "integer", "format": "int64", "example": 918273 },
          "cursor": { "type": "string", "minLength": 30, "maxLength": 30, "example": "000000000000010487100000000040" },
          "ts": { "type": "integer", "format": "int64", "example": 1785470168892 },
          "equity": { "type": "string", "example": "9200" },
          "im": { "type": "string", "example": "9800" },
          "mm": { "type": "string", "example": "4900" },
          "available": { "type": "string", "example": "0" },
          "ccy": { "type": "string", "example": "USD" }
        }
      },
      "Instrument": {
        "type": "object",
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-PERP" },
          "tradingPhase": { "type": "string", "nullable": true, "enum": ["CONTINUOUS", "CALL_OPEN", "CALL_CLOSE", "CLOSED"], "description": "2.33.0 (ADR-22): the phase in force on a SECURITY market with an auction schedule; absent on every other market. During CALL_OPEN, CALL_CLOSE and CLOSED limit orders rest for the uncross and nothing matches; IOC, FOK, MARKET and conditional orders reject 2046." },
          "auction": { "type": "object", "nullable": true, "description": "2.33.0 (ADR-22): the call auction schedule of a SECURITY market (local times in zone; opening call start and uncross, closing call start and uncross). Absent without a schedule.", "properties": { "schedule": { "type": "string", "example": "LOCAL_DAILY" }, "zone": { "type": "string", "example": "LONDON" }, "openCallStart": { "type": "string", "example": "07:50" }, "openUncross": { "type": "string", "example": "08:00" }, "closeCallStart": { "type": "string", "example": "16:20" }, "closeUncross": { "type": "string", "example": "16:30" } } },
          "lastAuctionPrice": { "type": "string", "nullable": true, "description": "2.33.0: the price of the last uncross that traded; the closing print is the DLT Market's daily valuation." },
          "lastAuctionTs": { "type": "integer", "format": "int64", "nullable": true, "description": "2.33.0: Unix ms of that uncross." },
          "kind": { "type": "string", "enum": ["PERP", "SPOT", "BARRIER", "SWAP", "SECURITY"], "example": "PERP",
            "description": "PERP (perpetual swap/future, margined, funded) | SPOT (prefunded base-asset delivery) | BARRIER (knock-out contracts, always RFQ) | SWAP (2.26.0: writer-first fixed yield contracts in one asset, always RFQ: offers are posted with POST /v1/rfq and taken with POST /v1/rfq/{rfqId}/accept; contracts under GET /v1/swaps) | SECURITY (2.32.0: a DLT financial instrument settled on the Kronos X chain, prefunded like SPOT, book or RFQ per mode; Member API section 6i)." },
          "mode": { "type": "string", "enum": ["ORDER_BOOK", "RFQ"], "example": "ORDER_BOOK",
            "description": "ORDER_BOOK (central limit order book) | RFQ (request-for-quote only: no book, order entry rejects with 2022, trade via POST /v1/rfq)." },
          "isin": { "type": "string", "nullable": true, "description": "ISO 6166 ISIN of the market where one exists; the sandbox values are test identifiers. null on BARRIER markets of a production venue: barrier contracts carry their own ISIN (2.35.0: the DSB ISIN of the contract's term set on the accept result and on GET /v1/barriers rows)." },
          "cfi": { "type": "string", "nullable": true },
          "baseAsset": { "type": "string", "example": "BTC" },
          "quoteAsset": { "type": "string", "example": "USD" },
          "settlementCcy": { "type": "string", "example": "USD" },
          "tickSize": { "type": "string", "example": "0.5",
            "description": "Price increment PER BASE UNIT (per BTC, per ETH). Prices misaligned to it reject with 2002." },
          "lotSize": { "type": "string", "example": "0.0001",
            "description": "Quantity increment in base units; always equals qtyStep." },
          "contractMultiplier": { "type": "string", "example": "1" },
          "qtyStep": { "type": "string", "example": "0.0001",
            "description": "The quantity grid: every qty must be an exact multiple of this step, at any decimal depth, else 2002. The venue never rounds a quantity. On a SPOT market the step is fractional exactly like on the perpetual of the same underlying (2.25.2: 0.0001 on BTC-USD, 0.001 on ETH-USD and BNB-USD, 0.01 on SOL-USD, 1 on XRP-USD), and a spot fill delivers exactly qty of the base asset against price x qty of the settlement currency; before 2.25.2 the description said spot traded whole units, which was true only of the earlier fixture, never a rule." },
          "minQty": { "type": "string", "example": "0.0001", "description": "Smallest accepted quantity; equals qtyStep on every current listing." },
          "minNotional": { "type": "string", "example": "5",
            "description": "Smallest accepted order value in the settlement currency: price times qty below this rejects with 2028. \"0\" means no floor. Priced orders are valued at the limit price, market orders at the current mark. Exempt: venue-initiated closes (liquidation, ADL) and reduceOnly orders within your reducible position, so a sub-floor residual can always be closed with a reduceOnly order of exactly the position size." },
          "maxOrderQty": { "type": "string", "example": "100000", "description": "Legacy per-order size cap in base units, like every quantity. Enforced (reject 2013) only when maxOrderNotional is not set; informational otherwise (maxOrderNotional takes precedence). Either way it is a fat-finger guard on a single order, not a risk capacity limit, and it applies to reduceOnly orders too." },
          "maxPositionQty": { "type": "string", "example": "1000000",
            "description": "Legacy position cap in base units. Enforced (reject 2011) only when maxPositionNotional is not set; informational otherwise." },
          "maxPositionNotional": { "type": "string", "nullable": true, "example": "2000000000",
            "description": "Position cap as notional in the settlement currency, valued at the CURRENT mark. When present it takes precedence over maxPositionQty: orders, amends or RFQ executions whose projected worst-case position would exceed it reject with 2011. A position already above the cap after a mark move is never forced to reduce; the cap only gates increases (risk-reducing flow always passes). Omitted when not set." },
          "maxOrderNotional": { "type": "string", "nullable": true, "example": "10000000",
            "description": "Per-order size cap as notional in the settlement currency. When present it takes precedence over maxOrderQty: a single order, amend, RFQ or quote whose price times qty would exceed it rejects with 2013 (priced orders valued at the limit price, market orders and RFQ creation at the current mark, quotes at the quoted entry). Applies to reduceOnly orders too, so closing a large position may take several orders; venue-initiated closes (liquidation, ADL) are exempt. Omitted when not set." },
          "priceBandBps": { "type": "integer", "format": "int64", "example": 1000 },
          "marketMaxSlippageBps": { "type": "integer", "format": "int64", "example": 500 },
          "makerFeeRate": { "type": "string", "example": "0.0002", "description": "The market's default maker rate as a decimal fraction of notional (negative = rebate). 2.35.0: every change of it is announced at least seven Business Days ahead on the Website and here (pendingFees); a tier rate applies on this market only where it is lower than this rate (section 7). On SWAP markets the rate every member pays (2.35.0, section 6h: fee tiers and programmes do not apply there)." },
          "takerFeeRate": { "type": "string", "example": "0.0005", "description": "The market's default taker rate, resolved like makerFeeRate. On SWAP markets the rate every member pays (2.35.0)." },
          "pendingFees": { "type": "object", "nullable": true, "description": "2.35.0: the ANNOUNCED change of this market's default maker and taker rates and the instant it applies (at least seven Business Days after the announcement, Rules s.29); absent while no change is pending. A member on a tier or enrolled in a programme on this market reads its own pending rows on GET /v1/account/parameters (account.fees.pending, kind INSTRUMENT where it trades at the market's rates).",
            "properties": { "makerFeeRate": { "type": "string", "example": "0.00025" }, "takerFeeRate": { "type": "string", "example": "0.0006" }, "effectiveFrom": { "type": "integer", "format": "int64", "example": 1760140800000 }, "effectiveFromIso": { "type": "string", "example": "2026-10-11T00:00:00Z" } } },
          "fundingIntervalHours": { "type": "integer", "format": "int64", "example": 8,
            "description": "The period one settlement's rate applies over: the grid interval on a GRID market, 24 on a LOCAL_DAILY market, 0 on spot and barrier markets which never fund." },
          "funding": { "$ref": "#/components/schemas/FundingSchedule" },
          "riskTiers": { "type": "array", "items": { "$ref": "#/components/schemas/RiskTier" } },
          "maxLeverage": { "type": "string", "nullable": true,
            "description": "Exact venue-wide leverage as a decimal string when the instrument runs one open-ended risk tier with an exact reciprocal IM rate (leverageMode FIXED); null otherwise, and omitted from the response when null. Null on every instrument listed today, because every listing is TIERED. This is the field to read before sending an order-level leverage assertion: where it is null, no assertion can be accepted." },
          "leverageMode": { "type": "string", "enum": ["FIXED", "TIERED"], "example": "TIERED",
            "description": "TIERED (several risk tiers, so the effective initial margin depends on position size) or FIXED (one open-ended tier at an exact reciprocal IM rate, and only then is maxLeverage non-null and an order-level leverage assertion accepted). Every instrument listed today is TIERED." },
          "knockOutRebateBps": { "type": "integer", "nullable": true, "example": 1000,
            "description": "BARRIER markets only (2.24.0): the knock-out REBATE in basis points of the barrier distance (0 = none; 1000 = 10 percent on every barrier market listed today). The holder's premium (its maximum loss) on a normal contract is (10000 - knockOutRebateBps) bps of |entry - barrier| x qty x contract value, and at a knock-out the holder recovers the rebate share from the writer. Frozen onto each contract when it opens (premiumBps on the contract), so a later change never re-prices an open contract. Omitted on PERP and SPOT." },
          "strictTakeProfitPremiumBps": { "type": "integer", "nullable": true, "example": 5000,
            "description": "BARRIER markets only (2.24.0): the STRICT take-profit premium share in basis points of the barrier distance (5000 = 50 percent on every barrier market listed today); 0 = strict take profit is NOT offered on this market and barrier.strictTakeProfit rejects 2027. A strict contract pays only if its take profit is touched before its expiry (at most 24 h after the request) and forfeits the whole premium at expiry otherwise, however close the mark is. Frozen onto each contract when it opens. Omitted on PERP and SPOT." },
          "swapMinTenorDays": { "type": "integer", "nullable": true, "example": 1,
            "description": "SWAP markets only (2.26.0): the shortest tenor an offer may name, whole days. Omitted on other kinds. On a swap market baseAsset is THE asset every money leg books in, minNotional is the minimum single take in that asset (there is no mark to value against), maxOrderQty caps one offer and one take, maxPositionQty caps your open swap size on the market in either role, tickSize is 1 (every price field on a swap market carries the rate in basis points), and funding, riskTiers and bands do not apply." },
          "swapMaxTenorDays": { "type": "integer", "nullable": true, "example": 365,
            "description": "SWAP markets only (2.26.0): the longest tenor an offer may name, whole days. Omitted on other kinds." },
          "swapMaxRateBps": { "type": "integer", "nullable": true, "example": 3000,
            "description": "SWAP markets only (2.26.0): the highest annualised rate an offer may name, basis points (3000 = 30 percent). Omitted on other kinds." },
          "markJumpRejectBps": { "type": "integer", "format": "int64", "example": 2000,
            "description": "2.27.0: the mark-jump guard: a mark tick further than this from the previous mark (basis points) is refused unless venue operations step the mark deliberately; 0 = off." },
          "staleMarkTimeoutSec": { "type": "integer", "format": "int64", "example": 60,
            "description": "2.27.0: the staleness timeout (section 10.9): the market turns reduce-only when its mark is older than this many seconds and resumes on the next fresh tick; 0 = staleness policy off." },
          "circuitBreaker": { "$ref": "#/components/schemas/CircuitBreaker" },
          "liquidation": { "$ref": "#/components/schemas/LiquidationParams" },
          "maxOpenOrdersPerMember": { "type": "integer", "format": "int64", "nullable": true, "example": 1000,
            "description": "2.27.0: the open-order ceiling per member on this market (reject 2012 beyond it); omitted when the market carries no per-market ceiling and only the account-wide cap on GET /v1/account/parameters applies." },
          "accessMode": { "type": "string", "enum": ["OPEN", "ADMISSION"], "example": "OPEN",
            "description": "2.27.0: OPEN, every member may trade the market; ADMISSION, only members admitted to the market under its published criteria may open new risk there (reject 3009 otherwise; reduce-only flow stays admitted). Since 2.35.0 the six swap markets are ADMISSION markets (the SWAP_COUNTERPARTY class of the Rules annex, member reference section 6h); every perpetual, spot and barrier market is OPEN. Your own admission is on GET /v1/account/parameters markets[].access. Open set." },
          "tradingHours": { "type": "string", "example": "CONTINUOUS",
            "description": "2.35.0: the trading hours of the market (Rulebook Section 12). CONTINUOUS on every listing without an auction schedule: 24 hours a day, every calendar day, weekends and public holidays included, no daily open, close or auction; trading there is interrupted only by a suspension, halt or removal, by the circuit breaker or by a reduce-only or post-only session, each announced on GET /v1/status, on status here and on the venueEvents channel. SCHEDULED on a SECURITY market that carries an auction schedule (member reference section 6j): its daily hours are the auction block of this row (opening call, uncross, closing call, uncross, local times in the market zone) and the phase in force is tradingPhase; GET /v1/status and venueEvents do not announce the CLOSED phase. Open set." },
          "barrierGuard": { "$ref": "#/components/schemas/BarrierGuard" },
          "strictTakeProfitMaxLifeHours": { "type": "integer", "format": "int64", "nullable": true, "example": 24,
            "description": "2.27.0, BARRIER markets only: the longest life of a strict take-profit contract in whole hours (a strict request with a later expiry rejects 2027)." },
          "maxContractLifeHours": { "type": "integer", "format": "int64", "nullable": true, "example": 8784,
            "description": "2.35.0, BARRIER markets only: the longest life of an opening contract in whole hours, measured from the request; a request without expiryTs or with a later one rejects 2027; absent when the market sets none (an omitted barrier.expiryTs is then open-ended)." },
          "barrierExpiryRequired": { "type": "boolean", "nullable": true, "example": false,
            "description": "2.35.0: true when this venue admits dated barrier contracts only (an opening request without barrier.expiryTs answers 2027); absent on other kinds." },
          "swapOfferValiditySec": { "$ref": "#/components/schemas/SwapOfferValidity" },
          "swapWriterEligibility": { "type": "string", "nullable": true, "enum": ["ANY", "MARKET_MAKER"], "example": "MARKET_MAKER",
            "description": "SWAP markets only (2.35.0): who may post OFFERS on this market. MARKET_MAKER: only a Market Maker Member, and only on its own account (no clientUid, or its house uid; reject 3013 otherwise), and an offer whose writer lost the designation is withdrawn at the next take (3007). ANY: every member (the sandbox until the venue announces activation). Every member may take. Open set; omitted on other kinds." },
          "status": { "type": "string", "example": "ACTIVE" }
        }
      },
      "SwapContract": {
        "type": "object",
        "description": "One yield contract you wrote or took (2.26.0). Live rows (status OPEN, or DEFAULTED while a claim stays outstanding) come from the venue registry; closed rows (status MATURED | CURED | FINAL_SETTLEMENT, only under ?status=CLOSED or ALL) from the venue's recent-closes ring and carry closedTs. The counterparty is never named. Every amount is in asset units of `asset`: notional is the principal that moved at the take, reward the reward frozen at the take (notional x rateBps x tenorDays / (10000 x 365), floor to 6 places; a FINAL_SETTLEMENT row carries the pro rata figure it settled at), paid what the writer has paid the taker so far and outstanding the claim still owed (nonzero on DEFAULTED rows only). Members that do not apply are omitted, never null.",
        "properties": {
          "contractId": { "type": "integer", "format": "int64", "example": 7 },
          "symbol": { "type": "string", "example": "BTC-STAKE-SWAP" },
          "asset": { "type": "string", "example": "BTC" },
          "role": { "type": "string", "enum": ["WRITER", "TAKER"], "example": "TAKER",
            "description": "WRITER received the principal at the take and owes principal plus reward at maturity; TAKER delivered the principal and holds the claim." },
          "qty": { "type": "string", "example": "0.5", "description": "The taken size, asset units." },
          "notional": { "type": "string", "example": "0.5", "description": "The principal that moved at the take, asset units (qty on every listing: one unit of qty is one unit of the asset)." },
          "rateBps": { "type": "integer", "format": "int64", "example": 450, "description": "Annualised rate the writer pays, basis points." },
          "tenorDays": { "type": "integer", "example": 30 },
          "reward": { "type": "string", "example": "0.001849", "description": "The frozen reward, asset units, ACT/365, floor." },
          "status": { "type": "string", "enum": ["OPEN", "DEFAULTED", "MATURED", "CURED", "FINAL_SETTLEMENT"], "example": "OPEN",
            "description": "OPEN: live, maturity ahead. DEFAULTED: the writer could not pay in full at maturity; what it could pay moved, the rest is an outstanding claim the venue re-tries every second from the writer's later balance (the writer is blocked from new offers, 3008, meanwhile). MATURED: principal plus reward paid in full at maturity. CURED: a defaulted claim paid to zero. FINAL_SETTLEMENT: operator close-out of a delisted swap market at principal plus the reward accrued pro rata by elapsed whole days." },
          "paid": { "type": "string", "example": "0", "description": "Cumulative asset units the writer has paid the taker on this contract." },
          "outstanding": { "type": "string", "example": "0", "description": "The claim still owed, asset units; nonzero on DEFAULTED rows only." },
          "openedTs": { "type": "integer", "format": "int64", "example": 1786464000000, "description": "The take, Unix ms." },
          "maturityTs": { "type": "integer", "format": "int64", "example": 1789056000000, "description": "openedTs + tenorDays x 24 h, Unix ms; the venue settles at the first sweep (1 s cadence) at or after it." },
          "closedTs": { "type": "integer", "format": "int64", "nullable": true, "description": "Closed rows only: when the contract closed, Unix ms." },
          "rfqId": { "type": "integer", "format": "int64", "example": 1207, "description": "The offer the contract was taken from." },
          "tradeId": { "type": "integer", "format": "int64", "example": 990312, "description": "The take's trade (flags SWAP), the contract's opening reference." },
          "clientUid": { "type": "string", "example": "CLIENT-A", "description": "Your side's end-client reference on the contract." }
        }
      },
      "FundingSchedule": {
        "type": "object", "nullable": true,
        "description": "How and when a perpetual's funding is set and settled (revision 3.42). OMITTED on spot and barrier markets, which never fund. schedule GRID is the historical fixed UTC anchor grid: one settlement every intervalHours at the last sequenced rate and mark. schedule LOCAL_DAILY is one settlement per calendar day at a local wall-clock window in zone (daylight saving applied by the venue): at snapshotLocalTime the venue captures every open position and the index; over vwapWindow it records one mark per minute (vwapSnapshots of them, at the minute boundaries counted back from the window end); at the window end it settles rate = clamp((mean of the recorded marks minus the index at the snapshot) / index at the snapshot, floor, cap), positive meaning longs pay, applied to the SNAPSHOT positions with the mean as the settle mark. A day with no position snapshot (venue outage across the snapshot time) is skipped, never charged later. Fields that do not apply to the schedule are omitted.",
        "properties": {
          "schedule": { "type": "string", "enum": ["GRID", "LOCAL_DAILY"], "example": "LOCAL_DAILY", "description": "Open set: build parsers that tolerate new values." },
          "intervalHours": { "type": "integer", "format": "int64", "nullable": true, "example": 8, "description": "GRID only: hours between settlement anchors." },
          "zone": { "type": "string", "enum": ["UTC", "LONDON", "NEW_YORK"], "nullable": true, "example": "NEW_YORK", "description": "LOCAL_DAILY only: the civil time zone the local times below are expressed in." },
          "snapshotLocalTime": { "type": "string", "nullable": true, "example": "16:00", "description": "LOCAL_DAILY only: local wall time (HH:MM) at which positions and the index are captured for the day's settlement." },
          "vwapWindow": { "type": "string", "nullable": true, "example": "15:55-16:00", "description": "LOCAL_DAILY only: local wall-time window (HH:MM-HH:MM) whose one-minute mark snapshots average into the settlement value; the settlement books at the window END." },
          "vwapSnapshots": { "type": "integer", "nullable": true, "example": 5, "description": "LOCAL_DAILY only: number of one-minute snapshots in the window." },
          "nextSettlementTs": { "type": "integer", "format": "int64", "nullable": true, "example": 1786464000000, "description": "Next settlement, Unix ms; the same instant as nextFundingTs. Omitted when none is scheduled." },
          "nextSnapshotTs": { "type": "integer", "format": "int64", "nullable": true, "example": 1786464000000, "description": "LOCAL_DAILY only: next position and index snapshot, Unix ms." },
          "rateCap": { "type": "string", "nullable": true, "example": "0.01", "description": "2.27.0: the highest rate one settlement may charge, decimal fraction per period; the settled rate is clamped to it." },
          "rateFloor": { "type": "string", "nullable": true, "example": "-0.01", "description": "2.27.0: the lowest rate one settlement may charge (negative = shorts pay longs)." },
          "rateSource": { "type": "string", "enum": ["TICK", "FIXED"], "nullable": true, "example": "TICK", "description": "2.27.0, GRID only: TICK, the rate the venue's reference feed stamps on each mark tick; FIXED, the market settles fixedRate every interval and ignores the tick's rate, and the rate in force and the predicted rate on every read surface (GET /v1/funding/current, GET /v1/ticker, the WebSocket get.funding request and the funding.{symbol} rate frame) read fixedRate. The source is a rule of each market: read it per market and never assume one value across listings (2.35.0: the sandbox crypto perpetuals publish FIXED). Open set." },
          "fixedRate": { "type": "string", "nullable": true, "example": "0.0001", "description": "2.27.0, GRID only, rateSource FIXED: the rate settled every interval, decimal fraction per period." }
        }
      },
      "CircuitBreaker": {
        "type": "object",
        "description": "2.27.0: the own-traded-price circuit breaker of a market (RTS 7 Art 19): a traded price more than bps from the reference inside windowSec halts the market, which auto-resumes after cooldownSec; bps 0 = no breaker.",
        "properties": {
          "bps": { "type": "integer", "format": "int64", "example": 1000 },
          "windowSec": { "type": "integer", "format": "int64", "example": 60 },
          "cooldownSec": { "type": "integer", "format": "int64", "example": 120 }
        }
      },
      "LiquidationParams": {
        "type": "object", "nullable": true,
        "description": "2.27.0, PERP markets only: the liquidation execution parameters in force on this market (section 7): the share of the remaining position closed per paced step (slicePercent), the smallest slice in base units (minSliceQty) and the IOC aggression band around the mark (aggressionBps). Each value names the scope that supplies it: MARKET when the market sets its own, VENUE when the venue value applies.",
        "properties": {
          "slicePercent": { "type": "string", "example": "20" },
          "slicePercentSource": { "type": "string", "enum": ["MARKET", "VENUE"], "example": "VENUE" },
          "minSliceQty": { "type": "string", "example": "0.0001" },
          "minSliceQtySource": { "type": "string", "enum": ["MARKET", "VENUE"], "example": "VENUE" },
          "aggressionBps": { "type": "integer", "format": "int64", "example": 50 },
          "aggressionBpsSource": { "type": "string", "enum": ["MARKET", "VENUE"], "example": "VENUE" }
        }
      },
      "BarrierGuard": {
        "type": "object", "nullable": true,
        "description": "2.27.0, BARRIER markets only: the quote guard in force (section 6b): the opening-accept band against a fresh mark (reject 2039 beyond it), the take-profit distance floor (2041) and the barrier distance floor (2042), all in basis points of the entry. 50 / 10 / 10 unless the market sets its own.",
        "properties": {
          "entryBandBps": { "type": "integer", "example": 50 },
          "minTakeProfitBps": { "type": "integer", "example": 10 },
          "minBarrierBps": { "type": "integer", "example": 10 }
        }
      },
      "SwapOfferValidity": {
        "type": "object", "nullable": true,
        "description": "2.27.0, SWAP markets only: the shortest and longest validity an offer may name (expiresInMs), in seconds; 60 to 2,592,000 unless the market sets its own. min is the rule the venue enforces on expiresInMs (2036 below it).",
        "properties": {
          "min": { "type": "integer", "format": "int64", "example": 60 },
          "max": { "type": "integer", "format": "int64", "example": 2592000 }
        }
      },
      "ParamValue": {
        "type": "object",
        "description": "2.27.0: one effective parameter value and the scope that supplies it. value is WRITTEN even when null (no rule at that scope). inert, when present, lists stored values a tighter scope beat, so what the venue stores for you and what is in force are both visible.",
        "properties": {
          "value": { "nullable": true, "description": "The effective value: an integer count, a decimal string, or null when no rule applies at any scope." },
          "source": { "type": "string", "enum": ["VENUE", "MARKET", "MEMBER", "MEMBER_MARKET", "SELF", "SELF_MARKET", "LEGACY", "INSTRUMENT", "TIER", "PROGRAMME"], "example": "MARKET", "description": "Open set. VENUE the venue value, MARKET the market rule, MEMBER a value venue operations set for your account on every market, MEMBER_MARKET one set for your account on this market, SELF and SELF_MARKET values you set yourself on PUT /v1/account/parameters (2.30.0: account-wide, or on this market), LEGACY the historical per-account quantity override, INSTRUMENT / TIER / PROGRAMME the fee resolution (2.35.0: a tier rate applies on a market only where it is lower than the market's own rate, per side; where it is not, the fee row reads INSTRUMENT with the tier rate inert); on SWAP market rows always INSTRUMENT (2.35.0: fee tiers and programmes do not apply on swap markets; a stored tier or programme value is listed under inert)." },
          "inert": { "type": "array", "nullable": true, "items": { "type": "object", "properties": { "source": { "type": "string" }, "value": { "nullable": true } } } }
        }
      },
      "AccountParameters": {
        "type": "object",
        "description": "2.27.0: every parameter the venue applies to YOUR account, with the scope that supplies each value (section 7, Your effective parameters). Market rules are public on GET /v1/instruments; this read shows what applies to you after every member-specific tightening, and only ever your own values.",
        "properties": {
          "asOfSeq": { "type": "integer", "format": "int64", "example": 1234567890 },
          "account": {
            "type": "object",
            "properties": {
              "maxOpenOrders": { "$ref": "#/components/schemas/ParamValue" },
              "imMultiplier": { "$ref": "#/components/schemas/ParamValue" },
              "withdrawalBuffer": { "$ref": "#/components/schemas/ParamValue" },
              "priceBandBps": { "$ref": "#/components/schemas/ParamValue" },
              "marketMaxSlippageBps": { "$ref": "#/components/schemas/ParamValue" },
              "maxOpenRfqs": { "$ref": "#/components/schemas/ParamValue" },
              "maxOpenContracts": { "$ref": "#/components/schemas/ParamValue" },
              "stp": { "type": "string", "enum": ["CANCEL_RESTING", "CANCEL_TAKER", "CANCEL_BOTH", "REJECT_TAKER"], "example": "CANCEL_RESTING" },
              "stpScope": { "type": "string", "enum": ["END_CLIENT", "MEMBER"], "example": "END_CLIENT" },
              "stpSource": { "type": "string", "enum": ["MEMBER", "SELF"], "example": "MEMBER", "description": "2.29.0: MEMBER (the account policy, elected on PUT /v1/account/stp or set at onboarding) or SELF (a value written under a self-service scope)." },
              "stpScopeSource": { "type": "string", "enum": ["MEMBER", "SELF"], "example": "MEMBER" },
              "rateLimits": { "type": "object", "description": "2.28.0: the published rate-limit class you sit in and the values in force (section 4): the class value or a tighter value venue operations set for you, never looser.", "properties": {
                "class": { "type": "string", "example": "STANDARD", "description": "The published class of the ladder (STANDARD = the venue default; DMA, MM and others as published)." }, "readsPerMin": { "type": "integer", "example": 6000 },
                "ordersPerMin": { "type": "integer", "example": 40000 }, "ordersPerSecBurst": { "type": "integer", "example": 0, "description": "Your class's per-SECOND ceiling on order entry, enforced beside the per-minute bucket (a 1003 with retryAfterMs under a second); 0 = none published for your class." },
                "source": { "type": "string", "enum": ["VENUE", "CLASS", "MEMBER"], "description": "Where ordersPerMin comes from: VENUE (the STANDARD class), CLASS (a published class), MEMBER (a tighter value of your own)." },
                "readsSource": { "type": "string", "enum": ["VENUE", "CLASS", "MEMBER"] }, "burstSource": { "type": "string", "enum": ["VENUE", "CLASS", "MEMBER"] } } },
              "otr": { "type": "object", "description": "2.28.0: the order-to-trade regime (section 4): your class, the thresholds in force (null = none), the published window and floor, and the prepared surcharge row. 2.35.0: the ratio is measured per member per market on the order-book markets (basis PER_INSTRUMENT, markets[].otr); state is the account-wide flag, a warning to venue operations only.", "properties": {
                "class": { "type": "string", "example": "STANDARD" }, "warn": { "type": "number", "nullable": true }, "block": { "type": "number", "nullable": true },
                "windowMinutes": { "type": "integer", "example": 60 }, "minOrders": { "type": "integer", "example": 100 },
                "source": { "type": "string", "enum": ["VENUE", "CLASS", "MEMBER"] },
                "basis": { "type": "string", "enum": ["PER_INSTRUMENT"], "example": "PER_INSTRUMENT", "description": "2.35.0: the calculation basis of the regime: the class threshold applies to each order-book market's own ratio (markets[].otr), never to the account-wide figure. Open set." },
                "state": { "type": "string", "enum": ["OK", "WARN"], "example": "OK", "description": "2.35.0: the account-wide flag over every market's messages: WARN when the account-wide ratio sits above the warn threshold (a flag to venue operations, never a block). Open set." },
                "surcharge": { "type": "object", "properties": { "enabled": { "type": "boolean", "example": false }, "bps": { "type": "number", "nullable": true } },
                  "description": "The OTR surcharge row of the published schedule: prepared, applied by nothing while enabled is false." } } },
              "dea": { "type": "object", "description": "2.28.0: your direct electronic access controls (section 4): the DEA-flow class and the limits in force on reg.dea orders per UTC day (null = none), today's use, and the DEA identifiers venue operations stopped on your account (reject 3010 on their reg.dea orders; 3011 at the flow limit).", "properties": {
                "class": { "type": "string", "example": "STANDARD" },
                "ordersPerDay": { "type": "integer", "format": "int64", "nullable": true }, "notionalPerDay": { "type": "string", "nullable": true },
                "source": { "type": "string", "enum": ["VENUE", "CLASS", "MEMBER"] },
                "usedToday": { "type": "object", "properties": { "orders": { "type": "integer", "format": "int64" }, "notional": { "type": "string" }, "day": { "type": "string", "example": "2026-09-10" } } },
                "stoppedIdentifiers": { "type": "array", "items": { "type": "string" } } } },
              "fees": { "type": "object", "description": "2.28.0: your fee resolution and measurement (section 7): the tier the published cycle measured you into (the member rates null when you trade at the instrument rates), the criteria and the figure measured, and every pending rate change with its effective date. 2.35.0: pending rows of kind INSTRUMENT list the announced default-rate changes of the markets where you trade at the market's own rates (no tier, no programme there); a tier rate applies on a market only where it is lower than that market's instrument rate (the market rows below). Stated since 2.40.0 (Member API revision 3.83, section 7; nothing changed): the object is never null, but measuredAt, volume30d and cycle read null until the first measured fee cycle that includes your account, and so do tier and criteria unless you are enrolled on a Market Maker Scheme tier, which they then name with its obligations (the first-of-month 00:00 UTC boundary: a member admitted after the last cycle, and every member of a venue started after it, reads null until the next one, unless venue operations run a measurement before it); a null there means not measured yet, never a fee of zero, and the fee deducted on each market is on every markets[] row, makerFeeRate and takerFeeRate with their source.", "properties": {
                "tier": { "type": "string", "nullable": true, "example": "STANDARD" }, "makerFeeRate": { "type": "string", "nullable": true }, "takerFeeRate": { "type": "string", "nullable": true },
                "criteria": { "type": "string", "nullable": true }, "measuredAt": { "type": "string", "nullable": true }, "volume30d": { "type": "string", "nullable": true }, "cycle": { "type": "string", "nullable": true, "example": "2026-10" },
                "pending": { "type": "array", "items": { "type": "object", "properties": {
                  "kind": { "type": "string", "enum": ["TIER", "PROGRAMME", "INSTRUMENT"], "description": "TIER your tier's dated rate change, PROGRAMME a programme you are enrolled in, INSTRUMENT (2.35.0) a market's announced default-rate change that moves what you pay there: every such change without a tier, and with a tier the changes that move the lower of your tier rate and the market rate on at least one side (a market a programme prices you on is never listed, nor one where your tier stays the lower rate on both sides before and after the change)." }, "name": { "type": "string" }, "symbol": { "type": "string", "nullable": true },
                  "makerFeeRate": { "type": "string" }, "takerFeeRate": { "type": "string" }, "effectiveFrom": { "type": "integer", "format": "int64" }, "effectiveFromIso": { "type": "string" } } } } } },
              "marginWatchPct": { "type": "number", "example": 80, "description": "The margin utilisation level at which venue operations send you an early warning (0 = off for your account)." },
              "legacy": { "type": "object", "properties": { "maxOrderQtyOverride": { "type": "integer", "format": "int64", "nullable": true, "description": "The historical per-account order-size override in contracts (the engine's unit), null when none; where set it appears as source LEGACY on markets[].maxOrderQty." } } }
            }
          },
          "markets": {
            "type": "array",
            "items": { "type": "object", "properties": {
              "symbol": { "type": "string", "example": "BTC-USD-PERP" },
              "access": { "$ref": "#/components/schemas/ParamValue" },
              "sessionStatus": { "$ref": "#/components/schemas/ParamValue" },
              "maxOpenOrders": { "$ref": "#/components/schemas/ParamValue" },
              "maxOrderNotional": { "$ref": "#/components/schemas/ParamValue" },
              "maxOrderQty": { "$ref": "#/components/schemas/ParamValue" },
              "maxPositionNotional": { "$ref": "#/components/schemas/ParamValue" },
              "maxPositionQty": { "$ref": "#/components/schemas/ParamValue" },
              "imMultiplier": { "$ref": "#/components/schemas/ParamValue" },
              "priceBandBps": { "$ref": "#/components/schemas/ParamValue" },
              "marketMaxSlippageBps": { "$ref": "#/components/schemas/ParamValue" },
              "maxOpenRfqs": { "$ref": "#/components/schemas/ParamValue" },
              "maxOpenContracts": { "$ref": "#/components/schemas/ParamValue" },
              "makerFeeRate": { "allOf": [{ "$ref": "#/components/schemas/ParamValue" }], "description": "2.35.0: the maker rate deducted on this market and its source. A tier rate applies on a market only where it is LOWER than the market's own rate, compared per side: on such a market the row carries the market's rate with source INSTRUMENT and your tier rate under inert, and that is the fee deducted there; where the tier rate is lower the row reads TIER; PROGRAMME on a market you are enrolled on." },
              "takerFeeRate": { "allOf": [{ "$ref": "#/components/schemas/ParamValue" }], "description": "2.35.0: the taker rate deducted on this market and its source, resolved per side exactly like makerFeeRate (a negative maker rebate is lower than any positive market rate and always applies; the taker side may read INSTRUMENT on the same market)." },
              "stp": { "type": "string" },
              "stpScope": { "type": "string" },
              "stpSource": { "type": "string", "enum": ["MEMBER", "SELF", "MEMBER_MARKET", "SELF_MARKET"], "description": "2.29.0: the scope that supplies the STP policy on this market (SELF_MARKET = your own per-market election on PUT /v1/account/stp with symbol)." },
              "stpScopeSource": { "type": "string", "enum": ["MEMBER", "SELF", "MEMBER_MARKET", "SELF_MARKET"] },
              "eligibilityRestricted": { "type": "boolean" },
              "otr": { "type": "object", "nullable": true, "description": "2.35.0: your order-to-trade figures on THIS market over the published window (section 4): the ring the block is decided on; absent on an RFQ-mode market (no ring there: quote messages are not counted). Zeros and OK while nothing was counted on the market.", "properties": {
                "orders": { "type": "integer", "format": "int64", "example": 0, "description": "Order messages counted on this market in the window: new orders, batch entries, amendments and the cancels you asked for (one per cancelled order)." },
                "trades": { "type": "integer", "format": "int64", "example": 0, "description": "Your ordinary fills on this market in the window: continuous-trading executions and call-auction executions (liquidation, ADL and reversal executions excluded)." },
                "ratio": { "type": "number", "nullable": true, "description": "orders over trades; null without a trade in the window (the regime then compares the message count against the floor)." },
                "state": { "type": "string", "enum": ["OK", "WARN", "BLOCK"], "example": "OK", "description": "The gate's answer on this market for your next order message: BLOCK rejects new orders, batch entries and amendments there with 1004 until the window slides back under the threshold; other markets are unaffected. Open set." },
                "windowMinutes": { "type": "integer", "example": 60 } } },
              "eligibility": { "type": "object", "description": "2.29.0: the Market Segments layers in force on this market (section 8): restricted when either layer narrows your counterparties; source VENUE (open to all), MEMBER (your account configuration) or MEMBER_MARKET (your per-market layer).", "properties": {
                "restricted": { "type": "boolean" },
                "source": { "type": "string", "enum": ["VENUE", "MEMBER", "MEMBER_MARKET"] },
                "memberLayer": { "type": "object", "properties": { "restricted": { "type": "boolean" }, "version": { "type": "integer" } } },
                "marketLayer": { "type": "object", "nullable": true, "properties": { "restricted": { "type": "boolean" }, "version": { "type": "integer" } } } } }
            } }
          },
          "self": { "type": "object", "description": "2.30.0: the values you set YOURSELF on PUT /v1/account/parameters, raw (section 7, Your own tighter limits): account is your account-wide block (absent while you set nothing there), markets one entry per market you wrote. A self value in force shows as source SELF or SELF_MARKET on the rows above; one a tighter scope beats shows under inert; one that merely ties the rule in force shows only here.",
            "properties": {
              "account": { "type": "object", "nullable": true, "additionalProperties": true, "example": { "priceBandBps": 300, "maxOpenRfqs": 8 } },
              "markets": { "type": "array", "items": { "type": "object", "properties": { "symbol": { "type": "string", "example": "BTC-USD-PERP" }, "values": { "type": "object", "additionalProperties": true, "example": { "maxOrderNotional": "250000", "maxPositionNotional": "500000" } } } } }
            } }
        }
      },
      "AccountParametersWrite": {
        "type": "object",
        "description": "2.30.0 (section 7, Your own tighter limits): set or clear your OWN limits on PUT /v1/account/parameters. Without symbol the write is account-wide (maxOpenOrders, imMultiplier, priceBandBps, marketMaxSlippageBps, maxOpenRfqs, maxOpenContracts); with symbol it is for that market alone (those plus maxOrderNotional, maxOrderQty, maxPositionNotional, maxPositionQty; the quantity names only on a market without the matching notional cap: on a market that carries maxOrderNotional a maxOrderQty value can bind nothing and is refused with 5003 and the sentence 'carries a notional order cap (maxOrderNotional applies there): set maxOrderNotional instead', the position twin likewise, and a quantity value stored earlier there reads under inert). A value can only TIGHTEN what is in force: the market rule, and any value venue operations set for your account at the same scope; a looser value is refused with 5003 and a sentence naming the rule. A cleared name reverts to the venue's rule. Not self-service: withdrawalBuffer, sessionStatus, access (venue measures) and stp / stpScope (PUT /v1/account/stp).",
        "properties": {
          "symbol": { "type": "string", "nullable": true, "example": "BTC-USD-PERP", "description": "Scope the write to this market. Omit for the account-wide values. Unknown symbol: 2001." },
          "set": { "type": "object", "additionalProperties": true, "example": { "maxOrderNotional": "250000", "priceBandBps": 300 }, "description": "Parameter name to value: counts and bps as integers, quantities, notionals and the multiplier as decimal strings." },
          "clear": { "type": "array", "items": { "type": "string" }, "example": ["maxPositionNotional"], "description": "Names to reset so the venue's rule applies again. A name cannot be in set and clear at once." }
        }
      },
      "AccountParametersWriteResult": {
        "type": "object",
        "description": "2.30.0: what was written and the effective values afterwards (parameters is exactly the GET /v1/account/parameters data).",
        "properties": {
          "scope": { "type": "string", "enum": ["ACCOUNT", "MARKET"] },
          "symbol": { "type": "string", "nullable": true },
          "set": { "type": "array", "items": { "type": "string" } },
          "cleared": { "type": "array", "items": { "type": "string" } },
          "parameters": { "$ref": "#/components/schemas/AccountParameters" }
        }
      },
      "RiskTier": {
        "type": "object",
        "description": "One margin tier. Tiers are ordered by ascending notionalCap and the last tier of every instrument is open-ended.",
        "properties": {
          "notionalCap": { "type": "string", "example": "1000000",
            "description": "Upper notional bound of this tier in the settlement currency, as a decimal string, EXCEPT on the open-ended last tier where the literal string \"max\" is published instead of a number. Parse defensively: a numeric parser that does not special-case \"max\" will fail on every instrument listed today." },
          "imRate": { "type": "string", "example": "0.02", "description": "Initial margin rate for this tier, as a decimal fraction." },
          "mmRate": { "type": "string", "example": "0.01", "description": "Maintenance margin rate for this tier, as a decimal fraction." }
        }
      },
      "RfqCreateRequest": {
        "type": "object",
        "required": ["symbol"],
        "description": "Three shapes share this body. An ORDINARY request carries side, qty and clientUid (all three required there: a missing side is 2013, a missing or off-grid qty 2002, a missing clientUid 2010 unless you are a market maker with a house account) and, on a barrier market, the barrier terms. A CLOSE REQUEST (2.23.0) carries closeContractId instead and MUST omit side, qty and barrier (2013): the venue derives them from the contract; clientUid may be omitted there. A yield contract OFFER (2.26.0, SWAP markets only) carries qty (the offered size in the asset), rateBps and tenorDays (both required, 2013 when absent), optionally minQty (the smallest single take, default the market's minimum) and expiresInMs (the offer's validity, default 24 h, engine bounds 60 s to 30 d), clOrdId, clientUid and reg; side, barrier and closeContractId MUST be omitted (2013). rateBps, tenorDays and minQty on any other market reject 2013. You are the WRITER of the offer: any other member may take a size of it (POST /v1/rfq/{rfqId}/accept with qty), you receive the taker's principal at the take and owe principal plus the reward at maturity; withdraw with POST /v1/rfq/{rfqId}/cancel. Terms outside the market's admission rule (rate above swapMaxRateBps, tenor outside swapMinTenorDays..swapMaxTenorDays, qty above maxOrderQty or below the market minimum, minQty above qty, validity outside 60 s..30 d) reject 2036; a writer with an outstanding claim from an earlier default is refused 3008; only a member the venue has designated as a Market Maker Member may post an offer, and only on its own account: a member that is not a Market Maker Member, or an offer carrying a clientUid other than your house uid, rejects 3013 (once GET /v1/instruments swapWriterEligibility reads MARKET_MAKER; revision 3.70), taking is open to every admitted member.",
        "properties": {
          "symbol": { "type": "string", "example": "BTC-USD-KO", "description": "Must be an RFQ-mode market (else code 2023). On a close request: the contract's market (else 2035)." },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY",
            "description": "Ordinary request only (required there; on a close request it must be omitted, 2013). On a barrier market this is the HOLDER direction: BUY = long (knocked out at or below the barrier), SELL = short (knocked out at or above)." },
          "qty": { "type": "string", "example": "1",
            "description": "Ordinary request only (required there; on a close request it must be omitted, 2013). Decimal base units on the instrument's qtyStep grid (2002 off-grid). Valued at the current mark against minNotional (2028 below it)." },
          "expiresInMs": { "type": "integer", "format": "int64", "example": 120000,
            "description": "Quoting window in ms (default 60000, bounds 1s to 24h). On a SWAP market (2.26.0) the same field is the OFFER VALIDITY: how long the offer stands on the board (default 86400000 = 24 h, bounds 60 s to 30 days, 2036 outside)." },
          "barrier": { "$ref": "#/components/schemas/BarrierTerms" },
          "clOrdId": { "type": "string", "maxLength": 36, "example": "my-rfq-1",
            "description": "Your reference, echoed on the request. Since 2.42.0, from the matching engine's replay-contract line for that release, a reference you already used answers 2009 (one namespace with your orders, swap takes and quotes). Before that line RFQ creation is NOT idempotent on clOrdId (stated since 2.40.0, Member API revision 3.83, sections 2 and 6b): a resend with the same clOrdId, identical or not, opens another request (or another swap offer) and never answers 2009, and order entry does not see an RFQ's reference; there, after a timeout read GET /v1/rfq/mine before you send again and withdraw a duplicate with the free POST /v1/rfq/{rfqId}/cancel. Keep it unique per member per 24 h as on order entry; the KX- prefix is reserved, code 2020. The example values on this page are placeholders: change the reference before every send. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced." },
          "clientUid": { "type": "string", "maxLength": 64, "example": "CLIENT-A",
            "description": "Ordinary request: required (2010) unless you are a market maker with a house account. Close request: OMIT it (it defaults to the contract's holder-side client) or send exactly that client (anything else is 2010). Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced." },
          "reg": { "$ref": "#/components/schemas/RegFields" },
          "closeContractId": { "type": "integer", "format": "int64", "example": 51,
            "description": "CLOSE REQUEST (2.23.0): the id of an OPEN barrier contract you HOLD on symbol (from GET /v1/barriers, role HOLDER). The request then asks the contract's WRITER to quote a price at which the contract closes early; side, qty and barrier MUST be omitted (2013) because the venue derives them: side is the CLOSING side (a long holder SELLs, a short holder BUYs), qty the full contract quantity, and the request carries the contract's barrier, takeProfit and contractExpiryTs informationally. Only the writer sees and may quote it; its price must lie STRICTLY INSIDE the contract's terms (2027 otherwise); accepting closes the contract AT the quoted price with terminationReason EARLY_CLOSE, fees like the entry trade. 2035 when the id is not an open contract you hold on this market, or a close request for it is already open (one at a time). Omit for an ordinary request." },
          "rateBps": { "type": "integer", "format": "int64", "example": 450,
            "description": "SWAP OFFER only (2.26.0): the annualised rate in basis points you (the writer) pay, 1..the market's swapMaxRateBps (2036 outside). Required on a swap market (2013 when absent); must be omitted on every other market (2013)." },
          "tenorDays": { "type": "integer", "example": 30,
            "description": "SWAP OFFER only (2.26.0): the tenor in whole days of every contract taken from this offer, within the market's swapMinTenorDays..swapMaxTenorDays (2036). Maturity = the take's time + tenorDays x 24 h. Required on a swap market (2013 when absent); must be omitted elsewhere (2013)." },
          "minQty": { "type": "string", "example": "0.01",
            "description": "SWAP OFFER only (2.26.0): the smallest size a single take may name, asset units on the qtyStep grid (zero or off the grid: 2002), at most qty (2036). Omit for the market's minimum (minNotional in asset units). A take may always name the offer's whole remainder, however small. Must be omitted on every other market (2013)." },
          "levelOrigin": { "type": "string", "enum": ["CLIENT", "DERIVED"], "example": "CLIENT",
            "description": "Barrier OPENING requests only (2.26.6, writer risk model): where the requested levels came from. CLIENT (the default) = the end client typed them; DERIVED = a routing system derived them from a pattern or template setup. Any other word is 2013; sending it on a close request or a non-barrier market is 2013 too. Frozen onto the contract at accept and shown to the WRITER beside capacity/clientTag; never read by any pricing or risk rule." },
          "clientClass": { "type": "string", "enum": ["RETAIL", "PROFESSIONAL", "ELIGIBLE"], "example": "RETAIL",
            "description": "Barrier OPENING requests only (2.26.6, writer risk model): the end client's MiFID II categorisation. Only meaningful with a clientUid; a request WITH a clientUid and WITHOUT this field defaults to RETAIL. Any other word is 2013; a close request or a non-barrier market refuses it (2013). Frozen onto the contract at accept and shown to the WRITER; never read by any pricing or risk rule." }
        }
      },
      "BarrierTerms": {
        "type": "object",
        "required": ["level"],
        "description": "Knock-out terms. REQUIRED on barrier markets, must be absent on perp/spot RFQ markets; invalid terms reject with 2027.",
        "properties": {
          "level": { "type": "string", "example": "60000",
            "description": "Knock-out level, on the instrument's tickSize grid. BUY (long holder): STRICTLY BELOW the current mark, and below the quoted entry; SELL (short holder): strictly above both. Checked against the mark at creation and again against the entry price at accept, so a level that was valid when it was written down stops being valid once the mark crosses it: read GET /v1/mark-price and place the level on the correct side before sending, rather than reusing a number from this page. On touch the contract settles AT this price, a guaranteed stop." },
          "expiryTs": { "type": "integer", "format": "int64", "example": 1893456000000,
            "description": "Contract expiry, Unix ms; OMIT for an open-ended contract, which is what most requests want on a market without maxContractLifeHours (open-ended only on a market without maxContractLifeHours). When present it must be in the future (a past timestamp rejects the request with 2027). Settles at mark on the first price tick at or past this time. 2.35.0: where the market publishes barrierExpiryRequired true (GET /v1/instruments) the venue lists dated contracts only and an opening request without expiryTs answers 2027 with the message 'this venue lists dated barrier contracts only: send barrier.expiryTs' before anything is journaled; the sandbox publishes false. 2.35.0: where the market publishes maxContractLifeHours (GET /v1/instruments) the expiry is REQUIRED and must lie at most that many hours after the request, measured at the request, else 2027; close requests are untouched." },
          "takeProfit": { "type": "string", "example": "70000",
            "description": "OPTIONAL take-profit level (revision 3.43), the second exit: OMIT for a knock-out-only contract. On the instrument's tickSize grid (2002 off it) and on the PROFIT side of the entry: BUY (long holder) STRICTLY ABOVE the current mark at creation and above the quoted entry at quote/accept; SELL (short holder) strictly below both (2027 otherwise), so the barrier and the take profit always sit on opposite sides of the entry. When the mark reaches it (long: at or above, short: at or below) the contract terminates AT this price, fee-free like a knock-out, zero-sum: the holder receives |takeProfit - entry| x qty in contract value. A gap through the level still settles AT it. Holder margin is unchanged; the writer's requirement becomes the smaller of the tiered figure and the remaining mark-to-take-profit distance. Same caveat as level: read GET /v1/mark-price and place it on the correct side before sending." },
          "strictTakeProfit": { "type": "boolean", "example": false,
            "description": "STRICT take profit (2.24.0): the contract pays ONLY if the take profit is touched before the contract expiry; at the expiry without a touch you (the holder) lose the whole premium whatever the mark. Requires takeProfit, expiryTs at most 24 h after the request, and a market whose strictTakeProfitPremiumBps is nonzero, else 2027 (re-checked at accept). Priced at strictTakeProfitPremiumBps of the barrier distance instead of the normal (10000 - knockOutRebateBps) share, i.e. much cheaper. Omit or send false for a normal contract (a body without it is byte-identical to 2.23.0)." }
        }
      },
      "RfqQuoteRequest": {
        "type": "object",
        "required": ["price", "clientUid"],
        "properties": {
          "price": { "type": "string", "example": "66000",
            "description": "On the instrument's tickSize grid and inside its price band (2003 outside it). On a barrier market this is the ENTRY price you offer as writer; it must sit above the barrier for a BUY RFQ and below it for a SELL (else 2027). The full RFQ quantity valued at this price is re-checked against minNotional (2028) and against the per-order notional cap (2013)." },
          "expiresInMs": { "type": "integer", "format": "int64", "example": 30000,
            "description": "Quote validity in ms (default 30000, bounds 1s to 24h)." },
          "clOrdId": { "type": "string", "maxLength": 36,
            "description": "Your reference for the quote, same rules as order entry. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced. Since 2.42.0, from the matching engine's replay-contract line for that release, a reference you already used answers 2009 with the msg 'clOrdId already used: an RFQ request or quote is never restated, read GET /v1/rfq/mine or GET /v1/rfq/quotes/mine', so a re-quote carries a new one." },
          "clientUid": { "type": "string", "maxLength": 64, "example": "CLIENT-B",
            "description": "The end client the quote is attributed to, as on order entry. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced." },
          "reg": { "$ref": "#/components/schemas/RegFields" },
          "premiumBps": { "type": "integer", "minimum": 1, "maximum": 10000, "example": 9500,
            "description": "Barrier OPENING requests only (2.26.6, writer risk model): your OWN premium share for THIS quote, integer basis points of the barrier distance. Allowed range: at least the market's effective share for the request's variant (normal: 10000 - knockOutRebateBps; strict: strictTakeProfitPremiumBps) and at most 10000, else 2044 PREMIUM_SHARE (you can only make a contract MORE expensive than the market base, never cheaper). On a close request or a non-barrier market: 2013. Omit for the market share. An accept freezes THIS share onto the contract exactly where the market share is frozen, and every premium, margin and settlement figure then reads the frozen share; the requester sees premiumBps on your quote before accepting." }
        }
      },
      "RfqAcceptRequest": {
        "type": "object",
        "description": "Two shapes. ACCEPT A QUOTE on your own RFQ (perp / spot / barrier): quoteId required, nothing else but reg (qty, clOrdId or clientUid alongside reject 2013). TAKE A YIELD CONTRACT OFFER (2.26.0, SWAP markets, the rfqId is another member's offer from GET /v1/rfq/open): qty required, NO quoteId (2037 if one is sent), clOrdId and clientUid as on order entry (clientUid required, 2010, unless you are a market maker with a house account), reg optional.",
        "properties": {
          "quoteId": { "type": "integer", "format": "int64", "example": 88, "description": "The quote you hit on your own RFQ. Omit (or 0) on a swap take." },
          "reg": { "$ref": "#/components/schemas/RegFields" },
          "qty": { "type": "string", "example": "0.5",
            "description": "SWAP TAKE only (2.26.0): the size you take, asset units on the offer market's qtyStep grid (zero or off the grid: 2002). At most the offer's remainingQty, at least its minQty unless it IS the remainder, within your per-order cap (maxOrderQty), else 2038. Your principal (qty in the asset) plus your taker fee must be payable from your balance in that asset (3004)." },
          "clOrdId": { "type": "string", "maxLength": 36, "example": "my-take-1", "description": "SWAP TAKE only: your reference, same rules as order entry (KX- reserved, 2020). Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced." },
          "clientUid": { "type": "string", "maxLength": 64, "example": "CLIENT-A", "description": "SWAP TAKE only: the end client the principal is attributed to; required (2010) unless you are a market maker with a house account. Since 2.36.0 a value that begins or ends with whitespace is rejected with code 2013 before anything is sequenced." }
        }
      },
      "Rfq": {
        "type": "object",
        "description": "An RFQ as seen by its requester (quotes included, makers anonymous) or on the open board (requester anonymous, quoteCount and myQuote instead). On a SWAP market (2.26.0) the row is a writer's standing OFFER: side is BUY (the writer receives the asset), qty the offered size, remainingQty what is still open to take, and rateBps / tenorDays / minQty / asset its terms; quotes, quoteCount and myQuote never apply (offers are taken, never quoted). The open board lists swap offers best-for-the-taker first: rate descending, then rfqId.",
        "properties": {
          "rfqId": { "type": "integer", "format": "int64", "example": 1207 },
          "symbol": { "type": "string", "example": "BTC-USD-KO" },
          "kind": { "type": "string", "enum": ["PERP", "SPOT", "BARRIER", "SWAP", "SECURITY"], "example": "BARRIER" },
          "rateBps": { "type": "integer", "format": "int64", "nullable": true, "example": 450, "description": "SWAP markets only (2.26.0): the annualised rate in basis points the writer pays. Omitted elsewhere." },
          "tenorDays": { "type": "integer", "nullable": true, "example": 30, "description": "SWAP markets only (2.26.0): the tenor in whole days of every contract taken from the offer. Omitted elsewhere." },
          "minQty": { "type": "string", "nullable": true, "example": "0.01", "description": "SWAP markets only (2.26.0): the smallest single take, asset units (a take may always name the whole remainder). Omitted elsewhere." },
          "remainingQty": { "type": "string", "nullable": true, "example": "0.4", "description": "SWAP markets only (2.26.0): the offered size not yet taken, asset units. Omitted elsewhere." },
          "asset": { "type": "string", "nullable": true, "example": "BTC", "description": "SWAP markets only (2.26.0): the asset every money leg books in. Omitted elsewhere." },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY" },
          "qty": { "type": "string", "example": "1" },
          "expiryTs": { "type": "integer", "format": "int64", "example": 1785470228892, "description": "End of the quoting window, Unix ms; on a SWAP market (2.26.0) the end of the offer's validity on the board." },
          "createdTs": { "type": "integer", "format": "int64", "example": 1785470168892 },
          "barrier": { "type": "string", "nullable": true, "example": "65000", "description": "Barrier markets only." },
          "takeProfit": { "type": "string", "nullable": true, "example": "70000", "description": "Barrier markets only (revision 3.43): the optional take-profit level; omitted on a knock-out-only request." },
          "contractExpiryTs": { "type": "integer", "format": "int64", "nullable": true, "description": "Barrier markets only; null = open-ended contract (open-ended only on a market without maxContractLifeHours)." },
          "closeContractId": { "type": "integer", "format": "int64", "nullable": true, "example": 51,
            "description": "Barrier markets only (2.23.0): the OPEN contract this request asks to CLOSE early; omitted on an ordinary request. A close request's side is the closing side, its qty the full contract quantity, and its barrier / takeProfit / contractExpiryTs are the contract's terms. It appears on the board of the contract's WRITER only." },
          "strictTakeProfit": { "type": "boolean", "nullable": true, "example": false,
            "description": "Barrier markets only (2.24.0): whether the request asks for a STRICT take-profit contract (a close request: whether the contract it closes is one). Omitted on perp / spot RFQ markets." },
          "premium": { "type": "string", "nullable": true, "example": "1440",
            "description": "Barrier markets only (2.24.0): the holder's PREMIUM (its maximum loss) as a 6-place money string. On an ordinary request it is INDICATIVE, valued at the CURRENT mark: |mark - barrier| x qty x contract value x premiumBps / 10000; the contract's premium is fixed only when a quote is accepted, at the quoted entry (see RfqAcceptResult.premium). On a close request it is the FROZEN premium of the contract being closed. Omitted on perp / spot RFQ markets and while the market has no mark." },
          "premiumBps": { "type": "integer", "nullable": true, "example": 9000,
            "description": "Barrier markets only (2.24.0): the premium share of the barrier distance in basis points the request would open at: 10000 - knockOutRebateBps on a normal request, the market's strictTakeProfitPremiumBps on a strict one (10000 = the full distance); a close request carries the contract's frozen share. Omitted on perp / spot RFQ markets." },
          "clOrdId": { "type": "string", "nullable": true, "description": "Requester view only; never on the open board." },
          "clientUid": { "type": "string", "nullable": true, "description": "Requester view only." },
          "quotes": { "type": "array", "nullable": true, "items": { "$ref": "#/components/schemas/RfqQuote" },
            "description": "Requester view only: live quotes on your RFQ, makers anonymous." },
          "quoteCount": { "type": "integer", "nullable": true, "description": "Open-board view only: number of live quotes." },
          "myQuote": { "$ref": "#/components/schemas/RfqQuote", "nullable": true, "description": "Open-board view only: your own live quote on this RFQ, if any." },
          "capacity": { "type": "string", "nullable": true, "enum": ["OWN_ACCOUNT", "FOR_CLIENT"], "example": "FOR_CLIENT",
            "description": "Open-board view only (2.26.5, writer transparency): FOR_CLIENT when the request carries an end-client reference, OWN_ACCOUNT when it rides the requesting member's house account. Never on your own requester views." },
          "clientTag": { "type": "string", "nullable": true, "example": "9f3a21bc00d14e77",
            "description": "Open-board view only (2.26.5, writer transparency): a 16-lowercase-hex-char pseudonym of the requester's end client, stable PER VIEWER (the same client of the same requester always tags the same toward you) and unlinkable across members; the raw clientUid is never derivable from it. Null on OWN_ACCOUNT rows." },
          "levelOrigin": { "type": "string", "nullable": true, "enum": ["CLIENT", "DERIVED"], "example": "CLIENT",
            "description": "Open-board view on barrier markets only (2.26.6, writer risk model): where the requested levels came from (a close request carries its contract's frozen value). Omitted elsewhere." },
          "clientClass": { "type": "string", "nullable": true, "enum": ["RETAIL", "PROFESSIONAL", "ELIGIBLE"], "example": "RETAIL",
            "description": "Open-board view on barrier markets, FOR_CLIENT rows only (2.26.6, writer risk model): the end client's MiFID II categorisation. Omitted on OWN_ACCOUNT rows and elsewhere." }
        }
      },
      "RfqQuote": {
        "type": "object",
        "properties": {
          "quoteId": { "type": "integer", "format": "int64", "example": 88 },
          "price": { "type": "string", "example": "66000" },
          "expiryTs": { "type": "integer", "format": "int64", "example": 1785470198892, "description": "End of quote validity, Unix ms." },
          "clOrdId": { "type": "string", "nullable": true, "description": "Your own maker views only; never exposed to the requester." },
          "rfqId": { "type": "integer", "format": "int64", "nullable": true, "description": "Maker views only: the RFQ this quote answers." },
          "symbol": { "type": "string", "nullable": true, "description": "Maker views only." },
          "premiumBps": { "type": "integer", "nullable": true, "example": 9500,
            "description": "The quote's OWN premium share in basis points (2.26.6, writer risk model), present on the requester's quote rows AND the maker's own views when the writer set one; omitted when the market share applies. The holder prices the contract's cost from this before accepting: an accept freezes it onto the contract." },
          "closeContractId": { "type": "integer", "format": "int64", "nullable": true,
            "description": "Maker views only (2.23.0): the contract the quoted RFQ asks to close when it is a close request (you wrote that contract); omitted on a quote against an ordinary request." }
        }
      },
      "RfqAcceptResult": {
        "type": "object",
        "description": "Perp / spot: the trade. Barrier open: plus contractId and the opened contract's terms. Barrier EARLY CLOSE (2.23.0, the accepted RFQ was a close request): contractId is the CLOSED contract, closeContractId echoes the request, settlePrice is the quoted price the contract settled at and realizedPnl your (holder) settlement P&L; the terms echo the closed contract's. Yield contract TAKE (2.26.0): quoteId is 0, side SELL (you delivered the asset), price the rate in basis points, contractId the opened swap contract (GET /v1/swaps) with notional, rateBps, tenorDays, reward, maturityTs, asset, your fee and the offer's remainingQty. Members that do not apply are omitted, never null.",
        "properties": {
          "rfqId": { "type": "integer", "format": "int64", "example": 1207 },
          "quoteId": { "type": "integer", "format": "int64", "example": 88 },
          "tradeId": { "type": "integer", "format": "int64", "example": 990312 },
          "symbol": { "type": "string", "example": "BTC-USD-KO" },
          "side": { "type": "string", "enum": ["BUY", "SELL"], "example": "BUY", "description": "Your (requester) side. On an early close: the closing side (a long holder SELLs, a short holder BUYs). On a swap take: SELL (you deliver the asset)." },
          "price": { "type": "string", "example": "66000", "description": "The traded price; on a swap take the rate in basis points." },
          "qty": { "type": "string", "example": "1" },
          "contractId": { "type": "integer", "format": "int64", "nullable": true, "example": 51,
            "description": "Barrier markets only: the opened contract, visible under GET /v1/barriers; on an early close (2.23.0) the CLOSED contract, visible under GET /v1/barriers?status=CLOSED. Swap take (2.26.0): the opened swap contract, visible under GET /v1/swaps." },
          "notional": { "type": "string", "nullable": true, "example": "0.5", "description": "Swap take only (2.26.0): the principal you delivered, asset units." },
          "rateBps": { "type": "integer", "format": "int64", "nullable": true, "example": 450, "description": "Swap take only: the annualised rate the writer pays, basis points." },
          "tenorDays": { "type": "integer", "nullable": true, "example": 30, "description": "Swap take only: the contract's tenor in whole days." },
          "reward": { "type": "string", "nullable": true, "example": "0.001849", "description": "Swap take only: the reward frozen on the contract, asset units (notional x rateBps x tenorDays / (10000 x 365), floor to 6 places)." },
          "maturityTs": { "type": "integer", "format": "int64", "nullable": true, "example": 1789056000000, "description": "Swap take only: maturity, Unix ms (the take's time + tenorDays x 24 h)." },
          "asset": { "type": "string", "nullable": true, "example": "BTC", "description": "Swap take only: the asset the principal, reward and fee book in." },
          "fee": { "type": "string", "nullable": true, "example": "0.0001", "description": "Swap take only: your taker fee in the asset, booked at the take (the only fee over the contract's life)." },
          "remainingQty": { "type": "string", "nullable": true, "example": "0.4", "description": "Swap take only: the offer's size still open after your take (0 when you took the remainder and the offer closed)." },
          "barrier": { "type": "string", "nullable": true, "example": "65000",
            "description": "Barrier markets only (revision 3.43): the contract's knock-out level, echoed." },
          "takeProfit": { "type": "string", "nullable": true, "example": "70000",
            "description": "Barrier markets only (revision 3.43): the contract's take-profit level; omitted when the contract has none." },
          "contractExpiryTs": { "type": "integer", "format": "int64", "nullable": true,
            "description": "Barrier markets only (revision 3.43): the contract's expiry, Unix ms; omitted when open-ended (open-ended only on a market without maxContractLifeHours)." },
          "closeContractId": { "type": "integer", "format": "int64", "nullable": true,
            "description": "Early close only (2.23.0): the accepted request's closeContractId, echoed (equal to contractId)." },
          "settlePrice": { "type": "string", "nullable": true, "example": "67000",
            "description": "Early close only (2.23.0): the price the contract settled at, the accepted quote's price." },
          "realizedPnl": { "type": "string", "nullable": true, "example": "1000",
            "description": "Early close only (2.23.0): your (holder) settlement P&L, direction x (settlePrice - entry) x qty x contract value, in the settlement currency, CLAMPED to [-premium, +potential profit] since 2.24.0; the writer books the negation. Fees are booked separately, like the entry trade's." },
          "strictTakeProfit": { "type": "boolean", "nullable": true, "example": false,
            "description": "Barrier markets only (2.24.0): whether the contract (opened, or closed early) is a STRICT take-profit one." },
          "premium": { "type": "string", "nullable": true, "example": "900",
            "description": "Barrier markets only (2.24.0): the contract's PREMIUM, the holder's maximum loss, |entry - barrier| x qty x contract value x premiumBps / 10000 (floor to 6 places), FROZEN at the open: what the holder margined at admission and what it loses at a knock-out (the writer receives it) or at a strict expiry without a touch." },
          "premiumBps": { "type": "integer", "nullable": true, "example": 9000,
            "description": "Barrier markets only (2.24.0): the contract's frozen premium share of the barrier distance in basis points (10000 = the full distance; 10000 - knockOutRebateBps on a normal contract; strictTakeProfitPremiumBps on a strict one)." },
          "uti": { "type": "string", "nullable": true, "example": "2138005EFA978Y43G944000000990312",
            "description": "2.35.0: EMIR unique transaction identifier of the venue leg: the venue LEI plus the trade id zero-padded to 12, on a PERP RFQ accept and a barrier entry or early close only (never a swap take), absent until the venue LEI is configured." },
          "isin": { "type": "string", "nullable": true, "example": "US5949181045",
            "description": "2.35.0: the DSB ISIN of the contract's term set (barrier markets only, the opened contract or the contract closed early); null until the venue has allocated it, always null where the venue files at market granularity (sandbox). Omitted on perp, spot and swap markets." },
          "ts": { "type": "integer", "format": "int64", "example": 1785470168892 }
        }
      },
      "BarrierContract": {
        "type": "object",
        "description": "One barrier contract you hold or wrote. Live rows (status OPEN, the default view) carry the mark-derived figures; closed rows (status CLOSED, only under ?status=CLOSED or ALL) carry the settlement instead: settlePrice, role-signed realizedPnl, terminationReason, closedTs. Members that do not apply are omitted, never null.",
        "properties": {
          "contractId": { "type": "integer", "format": "int64", "example": 51 },
          "symbol": { "type": "string", "example": "BTC-USD-KO" },
          "role": { "type": "string", "enum": ["HOLDER", "WRITER"], "example": "HOLDER" },
          "direction": { "type": "string", "enum": ["LONG", "SHORT"], "example": "LONG",
            "description": "Holder direction: LONG is knocked out at or below the barrier, SHORT at or above." },
          "qty": { "type": "string", "example": "1" },
          "entry": { "type": "string", "example": "66000" },
          "barrier": { "type": "string", "example": "65000" },
          "takeProfit": { "type": "string", "nullable": true, "example": "70000",
            "description": "The optional take-profit level (revision 3.43); omitted on a knock-out-only contract." },
          "strictTakeProfit": { "type": "boolean", "example": false,
            "description": "STRICT take-profit contract (2.24.0): pays only if the take profit is touched before expiryTs; the expiry without a touch settles at minus the premium whatever the mark (terminationReason EXPIRY, realizedPnl = -premium for the holder)." },
          "premium": { "type": "string", "example": "900",
            "description": "The holder's PREMIUM (2.24.0): its maximum loss on the contract, |entry - barrier| x qty x contract value x premiumBps / 10000 (floor to 6 places), frozen at the open. What the holder margined at admission; what it loses at a knock-out (the writer receives it) or at a strict expiry without a touch; the floor of every other settlement." },
          "premiumBps": { "type": "integer", "example": 9000,
            "description": "The frozen premium share of the barrier distance in basis points (2.24.0): 10000 = the full distance (every contract opened before the knock-out rebate existed), 10000 - the market's knockOutRebateBps on a normal contract, the market's strictTakeProfitPremiumBps on a strict contract." },
          "status": { "type": "string", "enum": ["OPEN", "CLOSED"], "example": "OPEN" },
          "markPrice": { "type": "string", "nullable": true, "example": "67200", "description": "Live rows only." },
          "barrierDistance": { "type": "string", "nullable": true, "example": "0.032738",
            "description": "Live rows only: distance from mark to the barrier as a decimal fraction of mark; \"0\" when at the knock-out." },
          "unrealizedPnl": { "type": "string", "nullable": true, "example": "1200", "description": "Live rows only: your unrealized P&L at mark, role-signed." },
          "margin": { "type": "string", "nullable": true, "example": "1000",
            "description": "Live rows only. Your margin: holder = the most you can still lose from here (the remaining mark-to-barrier distance less the knock-out rebate, i.e. the premium plus your unrealized P&L, floored at 0; 2.24.0), writer = tier margin on current notional, bounded by the remaining mark-to-take-profit distance when the contract carries a take profit." },
          "expiryTs": { "type": "integer", "format": "int64", "nullable": true, "description": "Unix ms; omitted = open-ended (open-ended only on a market without maxContractLifeHours)." },
          "clientUid": { "type": "string", "example": "CLIENT-A" },
          "capacity": { "type": "string", "nullable": true, "enum": ["OWN_ACCOUNT", "FOR_CLIENT"], "example": "FOR_CLIENT",
            "description": "WRITER rows only (2.26.5, writer transparency): the capacity the HOLDER side was entered in. Omitted on holder rows." },
          "clientTag": { "type": "string", "nullable": true, "example": "9f3a21bc00d14e77",
            "description": "WRITER rows only (2.26.5, writer transparency): your per-viewer pseudonymous tag of the holder's end client (see the Rfq schema's clientTag). Null on OWN_ACCOUNT contracts; omitted on holder rows." },
          "levelOrigin": { "type": "string", "nullable": true, "enum": ["CLIENT", "DERIVED"], "example": "CLIENT",
            "description": "WRITER rows only (2.26.6, writer risk model): the frozen origin of the contract's levels. Omitted on holder rows." },
          "clientClass": { "type": "string", "nullable": true, "enum": ["RETAIL", "PROFESSIONAL", "ELIGIBLE"], "example": "RETAIL",
            "description": "WRITER rows on FOR_CLIENT contracts only (2.26.6, writer risk model): the frozen MiFID II class of the holder's end client. Omitted otherwise." },
          "openedTs": { "type": "integer", "format": "int64", "example": 1785470168892 },
          "settlePrice": { "type": "string", "nullable": true, "example": "70000",
            "description": "Closed rows only: the settlement price (the barrier on a knock-out, the take-profit level on a take profit, the writer's accepted quote on an EARLY_CLOSE, the terms-clamped mark otherwise)." },
          "realizedPnl": { "type": "string", "nullable": true, "example": "4000", "description": "Closed rows only: your role-signed settlement P&L." },
          "terminationReason": { "type": "string", "nullable": true, "enum": ["KNOCK_OUT", "TAKE_PROFIT", "EXPIRY", "TEAR_UP", "FINAL_SETTLEMENT", "EARLY_CLOSE"], "example": "TAKE_PROFIT",
            "description": "Closed rows only. TEAR_UP = a party entered liquidation; FINAL_SETTLEMENT = operator close-out of a delisted market; EARLY_CLOSE (2.23.0) = the holder's close request accepted at the writer's quoted price (the one member-negotiated termination: it prints a BARRIER_CLOSE trade and pays fees like the entry)." },
          "closedTs": { "type": "integer", "format": "int64", "nullable": true, "description": "Closed rows only: settlement time, Unix ms." },
          "isin": { "type": "string", "nullable": true, "example": "US5949181045",
            "description": "2.35.0: the DSB ISIN of the contract's term set (barrier markets only; live and closed rows, holder and writer alike); null until the venue has allocated it, always null where the venue files at market granularity (sandbox)." }
        }
      },
      "ChainCustodyWalletRequest": {
        "type": "object", "required": ["clientUid"],
        "description": "2.35.0 (Member API 3.70, section 6i). The body of POST /v1/chain/wallets/custody: the venue derives the wallet id from your credential and the clientUid (WalletId.ForCustody), so no wallet id is sent.",
        "properties": {
          "clientUid": { "type": "string", "maxLength": 64, "example": "INV-1", "description": "Your end client's reference, the same string you send on orders (section 6d). Longer than 64 characters: 2013." },
          "professional": { "type": "boolean", "example": false, "description": "Whether the client is a professional client under the token's contract (professionalOnly tokens refuse a retail wallet at the block)." }
        }
      },
      "ChainTransferRequest": {
        "type": "object", "required": ["clientUid", "isin", "to", "units"],
        "description": "2.35.0 (section 6i). The body of POST /v1/chain/transfers: the SOURCE is your custody wallet for clientUid (derived, never named), the destination any wallet id on the chain.",
        "properties": {
          "clientUid": { "type": "string", "maxLength": 64, "example": "INV-1" },
          "isin": { "type": "string", "example": "XS0000000777", "description": "The token's ISIN, the SECURITY market's baseAsset." },
          "to": { "type": "string", "pattern": "^[0-9a-f]{64}$", "example": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "description": "The destination wallet id: 64 lowercase hex characters (the public explorer's wallet ids)." },
          "units": { "type": "integer", "format": "int64", "minimum": 1, "example": 100, "description": "Whole units at the token's unitScale; must be positive." }
        }
      },
      "ChainUnlockRequest": {
        "type": "object", "required": ["wallet", "isin", "units"],
        "description": "2.35.0 (section 6i). The body of POST /v1/chain/unlock: units of an EXTERNAL wallet you sponsor move from trading (locked) back to free; a custody wallet or a wallet another member sponsors is refused with 5003 and chain.reason.",
        "properties": {
          "wallet": { "type": "string", "pattern": "^[0-9a-f]{64}$", "example": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "description": "The sponsored external wallet's id, 64 lowercase hex characters." },
          "isin": { "type": "string", "example": "XS0000000777" },
          "units": { "type": "integer", "format": "int64", "minimum": 1, "example": 50 }
        }
      },
      "ChainInstructionRequest": {
        "type": "object", "required": ["kind", "signerKey", "signature"], "additionalProperties": true,
        "description": "2.35.0 (section 6i). The signed envelope of POST /v1/chain/instructions, the MEMBER subset: an instruction an external wallet's own key signed (DER ECDSA P-256 over SHA-256 of \"KXC:instr:\" and the canonical body, the SDK's encoder). The sponsor of an External wallet is always you, the authenticated member, never a field of the envelope. The registrar-only fields (token creation, issue, distribution, contract, corporate actions, validator changes) belong to the operator's routes and are not accepted here.",
        "properties": {
          "kind": { "type": "string", "enum": ["WalletRegister", "Lock", "Transfer"], "example": "Lock", "description": "WalletRegister (class External, you as sponsor), Lock (free to trading; credits your engine balance at finality) or Transfer. Any other value: 2013 with error unknown kind." },
          "auth": { "type": "string", "enum": ["WalletKey"], "default": "WalletKey", "example": "WalletKey", "description": "WalletKey is the only authorisation a member envelope may carry; a Sequencer or Registrar envelope is refused by the chain (5003, NotAuthorised)." },
          "tsNanos": { "type": "integer", "format": "int64", "description": "The instruction's timestamp, Unix nanoseconds; must fall inside the chain's instruction validity window." },
          "from": { "type": "string", "nullable": true, "pattern": "^[0-9a-f]{64}$", "description": "The source wallet id (Lock, Transfer)." },
          "to": { "type": "string", "nullable": true, "pattern": "^[0-9a-f]{64}$", "description": "The destination wallet id (Transfer)." },
          "isin": { "type": "string", "nullable": true, "example": "XS0000000777", "description": "The token's ISIN (Lock, Transfer); token is the same field under its chain name." },
          "token": { "type": "string", "nullable": true, "description": "The token id (Lock, Transfer); isin is the same field under its market name." },
          "units": { "type": "integer", "format": "int64", "example": 100 },
          "walletClass": { "type": "string", "nullable": true, "enum": ["External"], "description": "WalletRegister only: a member envelope registers External wallets." },
          "publicKey": { "type": "string", "nullable": true, "description": "WalletRegister only: the wallet's P-256 public key, hex." },
          "memberId": { "type": "integer", "description": "WalletRegister only: your member id as the sponsor; the venue takes the authenticated member regardless." },
          "clientRef": { "type": "string", "nullable": true, "pattern": "^[0-9a-f]{64}$", "description": "WalletRegister only, optional: the custody wallet id (64 lowercase hex characters) of your client the external wallet trades for; absent for a wallet you sponsor for yourself. No client identifier is ever sent in the envelope (the registration's clientUid left the layout at schema 2)." },
          "professional": { "type": "boolean" },
          "signerKey": { "type": "string", "description": "The signing wallet key, hex (the wallet's own key for WalletKey)." },
          "signature": { "type": "string", "description": "DER ECDSA P-256 over SHA-256(\"KXC:instr:\" || canonical body), hex." }
        }
      },
      "ChainInstructionStatus": {
        "type": "object",
        "description": "2.35.0 (section 6i). The status of one chain instruction as the member routes answer it under chain and as GET /chain/v1/instructions/{hash} serves it.",
        "properties": {
          "txHash": { "type": "string", "example": "1c1d6e4f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d", "description": "The instruction's hash, hex; the key of GET /chain/v1/instructions/{hash}." },
          "kind": { "type": "string", "example": "Transfer", "description": "The instruction kind (WalletRegister, Lock, Transfer, and the registrar kinds on the public record)." },
          "state": { "type": "string", "enum": ["Queued", "Included", "Final", "Rejected"], "example": "Queued", "description": "Queued until a block carries it, Included in a block not yet final, Final once attested by the quorum, Rejected with reason." },
          "height": { "type": "integer", "format": "int64", "example": -1, "description": "The block height once Final, -1 before." },
          "reason": { "type": "string", "example": "", "description": "Empty unless Rejected: the chain's refusal (ContractRefused, NotAuthorised, ...)." }
        }
      },
      "ChainInstructionResult": {
        "type": "object", "required": ["chain"],
        "description": "2.35.0. The 200 of the member chain writes (transfers, unlock, the signed envelope): NOT the standard envelope, the object { chain } as served.",
        "properties": { "chain": { "$ref": "#/components/schemas/ChainInstructionStatus" } }
      },
      "ChainCustodyWalletResult": {
        "type": "object", "required": ["chain", "walletId"],
        "description": "2.35.0 (Member API 3.70). The 200 of POST /v1/chain/wallets/custody: NOT the standard envelope, { chain, walletId } as served; walletId is the venue's keyed derivation for that client (never computable by the caller), the clientRef of an external wallet registration and the id GET /v1/chain/wallets lists.",
        "properties": {
          "chain": { "$ref": "#/components/schemas/ChainInstructionStatus" },
          "walletId": { "type": "string", "pattern": "^[0-9a-f]{64}$", "example": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "description": "The custody wallet id, 64 lowercase hex characters." }
        }
      },
      "ChainWalletBalance": {
        "type": "object",
        "properties": {
          "isin": { "type": "string", "example": "XS0000000777" },
          "free": { "type": "integer", "format": "int64", "example": 0, "description": "Units not in trading." },
          "locked": { "type": "integer", "format": "int64", "example": 380, "description": "Units in trading (delivered to the engine for the SECURITY market)." },
          "unitScale": { "type": "integer", "example": 1 }
        }
      },
      "ChainWallet": {
        "type": "object",
        "description": "2.35.0 (section 6i). One wallet of yours on the chain as GET /v1/chain/wallets serves it; the public explorer never shows clientUid.",
        "properties": {
          "id": { "type": "string", "example": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "description": "The wallet id, 64 hex characters." },
          "class": { "type": "string", "enum": ["Custody", "External", "Issuer", "Treasury"], "example": "Custody", "description": "Custody (the venue holds the key: your client's wallet, or your house wallet with an empty clientUid), External (a wallet you sponsor with its own key); Issuer and Treasury wallets belong to the registrar and never appear on your read." },
          "clientUid": { "type": "string", "nullable": true, "example": "INV-1", "description": "Your client's reference on a custody wallet; empty on a house or external wallet." },
          "house": { "type": "boolean", "example": false, "description": "True on your house custody wallet (the empty clientUid)." },
          "status": { "type": "string", "enum": ["Active", "Frozen"], "example": "Active", "description": "Frozen when a registrar measure is in force (revision 3.70): orders, amends, RFQ requests, quotes and accepts for the wallet's client answer 2049 TOKEN_RESTRICTED, and the client's resting orders, open RFQ requests and live quotes on SECURITY markets are cancelled when the measure is taken; nothing else about the measure is served." },
          "professional": { "type": "boolean", "example": false },
          "hasOwnKey": { "type": "boolean", "example": false },
          "publicKey": { "type": "string", "nullable": true, "description": "The wallet's own P-256 public key, hex; null unless hasOwnKey." },
          "clientRef": { "type": "string", "nullable": true, "description": "The custody wallet id an external wallet registration named as the client it trades for (revision 3.70), hex; null when none." },
          "balances": { "type": "array", "items": { "$ref": "#/components/schemas/ChainWalletBalance" } }
        }
      },
      "ChainWalletsResult": {
        "type": "object", "required": ["height", "wallets"],
        "description": "2.35.0. The 200 of GET /v1/chain/wallets: NOT the standard envelope, { height, wallets } as served.",
        "properties": {
          "height": { "type": "integer", "format": "int64", "example": 12, "description": "The chain height the wallets were read at." },
          "wallets": { "type": "array", "items": { "$ref": "#/components/schemas/ChainWallet" } }
        }
      },
      "ChainSettlement": {
        "type": "object",
        "description": "2.35.0 (section 6i). One settlement obligation of yours, a fill on a SECURITY market, as GET /v1/chain/settlements serves it (a bare array of these, or one object with ?tradeId=).",
        "properties": {
          "tradeId": { "type": "integer", "format": "int64", "example": 990312 },
          "engineSeqNo": { "type": "integer", "format": "int64", "example": 118234 },
          "isin": { "type": "string", "example": "XS0000000777" },
          "units": { "type": "integer", "format": "int64", "example": 120 },
          "state": { "type": "string", "enum": ["Pending", "Settled", "Failed"], "example": "Settled" },
          "height": { "type": "integer", "format": "int64", "example": 14, "description": "The block height of the DvpSettle once Settled, -1 before." },
          "txHash": { "type": "string", "nullable": true, "description": "The DvpSettle transaction hash once Settled." },
          "houseCoveredUnits": { "type": "integer", "format": "int64", "example": 0, "description": "Units the venue's house wallet covered for a short seller (the settlement discipline of the DLT annex)." },
          "reason": { "type": "string", "example": "" },
          "observedUtcMs": { "type": "integer", "format": "int64", "example": 1786464000000 },
          "settledUtcMs": { "type": "integer", "format": "int64", "example": 1786464002000, "description": "0 until Settled." }
        }
      },
      "ChainHead": {
        "type": "object",
        "description": "2.35.0 (section 6i). The public chain head as GET /chain/v1/head serves it (no envelope).",
        "properties": {
          "network": { "type": "string", "example": "kronosx-dev" },
          "schemaVersion": { "type": "integer", "example": 1 },
          "height": { "type": "integer", "format": "int64", "example": 14, "description": "-1 before the genesis block." },
          "blockHash": { "type": "string", "nullable": true, "description": "The head block's hash, hex." },
          "stateRoot": { "type": "string", "nullable": true, "description": "The state root the head commits to, hex." },
          "tsNanos": { "type": "integer", "format": "int64", "example": 0 },
          "time": { "type": "string", "example": "2026-09-10T12:00:00Z" },
          "validators": { "type": "integer", "example": 4, "description": "The validator set in force for the NEXT block." },
          "quorum": { "type": "integer", "example": 3 },
          "externalValidators": { "type": "integer", "example": 2, "description": "Revision 3.70: the validators of the set in force not operated by the venue operator." },
          "headSignatures": { "type": "integer", "example": 4, "description": "Valid attestations on the head block, counted against the set that signed it (headValidators, headQuorum)." },
          "headValidators": { "type": "integer", "example": 4, "description": "Revision 3.70: the size of the set that signed the head block." },
          "headQuorum": { "type": "integer", "example": 3, "description": "Revision 3.70: the quorum of the set that signed the head block." },
          "requireExternal": { "type": "boolean", "example": true, "description": "Whether finality needs at least one external validator's attestation." },
          "unattestedTail": { "type": "boolean", "example": false, "description": "True while the newest block has not reached the quorum." },
          "leader": { "type": "boolean", "example": true, "description": "Whether the answering node produces blocks." },
          "tokens": { "type": "integer", "example": 2 },
          "wallets": { "type": "integer", "example": 9 },
          "balances": { "type": "integer", "example": 11 },
          "settledTrades": { "type": "integer", "example": 3 },
          "blocksProducedSinceStart": { "type": "integer", "format": "int64", "example": 14 },
          "avgFinalityMs": { "type": "number", "example": 210.5 },
          "maxFinalityMs": { "type": "integer", "format": "int64", "example": 480 },
          "blockIntervalMs": { "type": "integer", "example": 1000 }
        }
      }
    }
  },
  "paths": {
    "/v1/time": {
      "get": { "tags": ["Public market data"], "operationId": "getServerTime", "summary": "Server time",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "object", "properties": {
            "serverTime": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Venue time, Unix ms. Sign X-TIMESTAMP against this to stay inside the 5 second receive window." }
          } } } }
        ] } } } } } }
    },
    "/v1/status": {
      "get": { "tags": ["Public market data"], "operationId": "getStatus", "summary": "Venue and per-instrument status",
        "description": "Legacy `venue`/`status` fields are retained verbatim (ACTIVE, HALTED, REDUCEONLY, POSTONLYSESSION, DELISTED). The additive `venueTradingState`/`tradingState`, `reason`, `since` and `expectedResumeTs` fields use the venueEvents vocabulary (TRADING, HALTED, REDUCE_ONLY, POST_ONLY, DELISTED; reasons ADMINISTRATIVE, CIRCUIT_BREAKER, STALE_MARK_PRICE, DELISTING). Null-valued additive fields are omitted.",
        "responses": { "200": { "description": "OK", "content": { "application/json": {
          "schema": { "type": "object", "properties": {
            "code": { "type": "integer" }, "msg": { "type": "string" },
            "data": { "type": "object", "properties": {
              "venue": { "type": "string", "enum": ["ACTIVE", "HALTED"] },
              "venueTradingState": { "type": "string", "enum": ["TRADING", "HALTED"] },
              "venueReason": { "type": "string", "nullable": true },
              "venueSince": { "type": "integer", "format": "int64", "nullable": true },
              "instruments": { "type": "array", "items": { "type": "object", "properties": {
                "symbol": { "type": "string" },
                "status": { "type": "string", "enum": ["ACTIVE", "HALTED", "REDUCEONLY", "POSTONLYSESSION", "DELISTED"] },
                "tradingState": { "type": "string", "enum": ["TRADING", "HALTED", "REDUCE_ONLY", "POST_ONLY", "DELISTED"] },
                "reason": { "type": "string", "nullable": true, "enum": ["ADMINISTRATIVE", "CIRCUIT_BREAKER", "STALE_MARK_PRICE", "DELISTING"] },
                "since": { "type": "integer", "format": "int64", "nullable": true },
                "expectedResumeTs": { "type": "integer", "format": "int64", "nullable": true }
              } } },
              "seqNo": { "type": "integer", "format": "int64" }
            } },
            "asOfSeq": { "type": "integer", "format": "int64" }, "ts": { "type": "integer", "format": "int64" }
          } },
          "example": { "code": 0, "msg": "ok",
            "data": { "venue": "ACTIVE", "venueTradingState": "TRADING",
              "instruments": [ { "symbol": "BTC-USD-PERP", "status": "HALTED", "tradingState": "HALTED",
                "reason": "CIRCUIT_BREAKER", "since": 1785000123456, "expectedResumeTs": 1785000243456 } ],
              "seqNo": 904118 },
            "asOfSeq": 904118, "ts": 1785000400000 }
        } } } } }
    },
    "/v1/instruments": {
      "get": { "tags": ["Public market data"], "operationId": "getInstruments", "summary": "Instrument specifications",
        "description": "Includes kind (PERP, SPOT or BARRIER), mode (ORDER_BOOK or RFQ), the per-base-unit tickSize, the quantity grid (qtyStep, minQty) and minNotional floor, fees, risk tiers, funding interval, and ISIN/CFI reference data. Align every price to tickSize and every quantity to qtyStep and respect minNotional; the venue rejects (2002/2028) rather than rounds. SPOT rows (2.25.2: BTC-USD, ETH-USD, SOL-USD, BNB-USD, XRP-USD on the sandbox) carry the same tickSize and qtyStep as the perpetual of the same underlying and no funding block; any riskTiers on a SPOT row are configuration echo, never applied: a spot order is prefunded, never margined. maxLeverage (exact decimal string) with leverageMode FIXED is published when the instrument runs a single open-ended risk tier with an exact reciprocal IM rate; otherwise maxLeverage is null and leverageMode is TIERED. Read these instead of hard-coding a leverage assertion. 2.35.0: every row carries tradingHours (open set): CONTINUOUS on every listing without an auction schedule (no daily open, close or auction; interruptions are announced on GET /v1/status and the venueEvents channel), SCHEDULED on a SECURITY market with one (its hours are the auction block of the row and its phase in force is tradingPhase, member reference section 6j).",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Instrument" } } } }
        ] } } } } } }
    },
    "/v1/orderbook": {
      "get": { "tags": ["Public market data"], "operationId": "getOrderBook", "summary": "Order book with checksum",
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "depth", "in": "query", "schema": { "type": "integer", "enum": [1, 5, 25, 100] }, "example": 5 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Book" } } }
        ] } } } } } }
    },
    "/v1/trades": {
      "get": { "tags": ["Public market data"], "operationId": "getTrades", "summary": "Recent public trades",
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "limit", "in": "query", "schema": { "type": "integer" }, "example": 20 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Trade" } } } }
        ] } } } } } }
    },
    "/v1/klines": {
      "get": { "tags": ["Public market data"], "operationId": "getKlines", "summary": "OHLCV candles for charting",
        "description": "Candlestick / OHLCV series for a market, oldest first. interval is one of 1m, 5m, 15m, 30m, 1h, 4h, 1d (default 1h); any other value answers 400. limit is 1 to 1000 (default 200). from (Unix ms) sets an earlier start but the window is bounded to the most recent limit intervals, so a call never returns more than limit candles ending at the present. Each row's t is the bucket open time (Unix ms); open, high, low and close are trade prices within the bucket by engine sequence; volume is the summed traded quantity; trades is the number of trades in the bucket.",
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "interval", "in": "query", "schema": { "type": "string", "enum": ["1m", "5m", "15m", "30m", "1h", "4h", "1d"], "default": "1h" }, "example": "1h" },
          { "name": "from", "in": "query", "description": "Earliest bucket open time, Unix ms. Bounded to the most recent limit intervals.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 200 }, "example": 200 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": {
            "t": { "type": "integer", "format": "int64", "example": 1700000000000, "description": "Bucket open time, Unix ms." },
            "open": { "type": "string", "example": "64980" },
            "high": { "type": "string", "example": "65010" },
            "low": { "type": "string", "example": "64950" },
            "close": { "type": "string", "example": "65000" },
            "volume": { "type": "string", "example": "12.5", "description": "Summed traded base quantity in the bucket." },
            "trades": { "type": "integer", "format": "int64", "example": 42, "description": "Number of trades in the bucket." }
          } } } } }
        ] } } } },
          "429": { "description": "2.35.0: the public candle gate (code 1003 with data.retryAfterMs and Retry-After): the anonymous per-peer window or the route-wide concurrency budget of the two candle routes, independent of your member buckets." } } }
    },
    "/v1/mark-klines": {
      "get": { "tags": ["Public market data"], "operationId": "getMarkKlines", "summary": "Mark-price candles",
        "description": "The venue mark price folded per interval from its one-minute mark history, oldest first: open is the first minute's open, close the last minute's close, high and low the extremes, ticks the number of mark updates in the bucket. There is no volume because the mark is not a trade. interval is one of 1m, 5m, 15m, 30m, 1h, 4h, 1d (default 1h); any other value answers 400. limit is 1 to 1000 (default 200). from (Unix ms) sets an earlier start but the window is bounded to the most recent limit intervals, so a call never returns more than limit candles ending at the present. A market that has no mark (a swap market, a market never ticked) answers an empty array. This is the series a perpetual is margined and funded on and a barrier contract is valued, knocked out and takes profit on.",
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "interval", "in": "query", "schema": { "type": "string", "enum": ["1m", "5m", "15m", "30m", "1h", "4h", "1d"], "default": "1h" }, "example": "1h" },
          { "name": "from", "in": "query", "description": "Earliest bucket open time, Unix ms. Bounded to the most recent limit intervals.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 200 }, "example": 200 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": {
            "t": { "type": "integer", "format": "int64", "example": 1700000000000, "description": "Bucket open time, Unix ms." },
            "open": { "type": "string", "example": "64980" },
            "high": { "type": "string", "example": "65010" },
            "low": { "type": "string", "example": "64950" },
            "close": { "type": "string", "example": "65000" },
            "ticks": { "type": "integer", "format": "int64", "example": 60, "description": "Number of mark updates in the bucket." }
          } } } } }
        ] } } } },
          "429": { "description": "2.35.0: the public candle gate (code 1003 with data.retryAfterMs and Retry-After): the anonymous per-peer window or the route-wide concurrency budget of the two candle routes, independent of your member buckets." } } }
    },
    "/v1/ticker": {
      "get": { "tags": ["Public market data"], "operationId": "getTicker", "summary": "Top of book, last, mark, index, funding, open interest",
        "parameters": [{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Ticker" } } }
        ] } } } } } }
    },
    "/v1/index-price": {
      "get": { "tags": ["Public market data"], "operationId": "getIndexPrice", "summary": "Index price",
        "parameters": [{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "object", "properties": {
            "symbol": { "type": "string", "example": "BTC-USD-PERP" },
            "indexPrice": { "type": "string", "nullable": true, "example": "68998", "description": "Null until the market has an index price." },
            "srcTs": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Source timestamp of the underlying tick, Unix ms." }
          } } } }
        ] } } } } } }
    },
    "/v1/mark-price": {
      "get": { "tags": ["Public market data"], "operationId": "getMarkPrice", "summary": "Mark price",
        "parameters": [{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "object", "properties": {
            "symbol": { "type": "string", "example": "BTC-USD-PERP" },
            "markPrice": { "type": "string", "nullable": true, "example": "69000", "description": "Null until the market has a mark (orders reject with 3005 in that state)." },
            "srcTs": { "type": "integer", "format": "int64", "example": 1785470168892, "description": "Source timestamp of the underlying tick, Unix ms." }
          } } } }
        ] } } } } } }
    },
    "/v1/funding/current": {
      "get": { "tags": ["Public market data"], "operationId": "getCurrentFunding", "summary": "Current and predicted funding rate, next settlement time",
        "description": "fundingRate is the rate in force for the current interval on a GRID market (OMITTED on a LOCAL_DAILY market with fundingRatePct, fundingRateAnnualizedPct and fundingPerUnit: the day's rate is computed at the snapshot and published on the settlement frame and GET /v1/funding/history); predictedFundingRate is the running estimate for the next one; nextFundingTs is the next settlement anchor (Unix ms).\n\nRATES ARE FRACTIONS, NOT AMOUNTS. fundingRate is a dimensionless fraction of position notional per interval: 0.0001 means 0.01% per interval, so a 100000 USD long pays 10 USD at each settlement while it holds. fundingRatePct is the same number as a percentage and fundingRateAnnualizedPct scales it to a year for venue comparison. The currency-denominated figure is the PAYMENT, booked in settleCcy: read it back as accFunding on GET /v1/positions and GET /v1/positions/end-clients, or as FUNDINGPAY / FUNDINGRECEIVE rows on GET /v1/account/ledger.",
        "parameters": [{ "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "object", "properties": {
            "symbol": { "type": "string", "example": "BTC-USD-PERP" },
            "fundingRate": { "type": "string", "nullable": true, "example": "0.0001", "description": "Dimensionless fraction of notional per interval, not a currency amount. GRID markets only: OMITTED (not null) on a LOCAL_DAILY market, where no rate is in force between the daily settlements." },
            "predictedFundingRate": { "type": "string", "nullable": true, "example": "0.00012", "description": "The running estimate for the next settlement. Always present on a GRID market. On a LOCAL_DAILY market it is the rate the marks recorded so far would settle at, and it is OMITTED (not null, never a fabricated zero) before the day's window opens." },
            "fundingRatePct": { "type": "string", "nullable": true, "example": "0.01", "description": "fundingRate as a percentage: the same number scaled by 100. Omitted whenever fundingRate is." },
            "predictedFundingRatePct": { "type": "string", "nullable": true, "example": "0.012", "description": "Omitted whenever predictedFundingRate is." },
            "fundingRateAnnualizedPct": { "type": "string", "nullable": true, "example": "10.95", "description": "rate x (365 days / period) x 100 where the period is fundingIntervalHours (24 on a LOCAL_DAILY market), simple, no compounding. OMITTED (not null) when the market has no funding grid." },
            "fundingPerUnit": { "type": "string", "nullable": true, "example": "6.5", "description": "A DISPLAY figure, not the figure to multiply (stated since 2.40.0, Member API revision 3.83, section 7; nothing changed): the charge of ONE qtyStep (one lot) at the current mark, rounded half-even to the micro of settleCcy, divided by the qtyStep, per settlement. qty x fundingPerUnit can differ from the booked charge by up to half a micro per qtyStep held, and the figure reads 0 when one lot's charge is at most half a micro. A booked charge is reproduced exactly as netQty x markPrice x contractMultiplier x fundingRate rounded half-even to the micro, on the member net position and on each client sub-position, the member charge minus the sum of the client charges added to the sub-position with the largest absolute netQty; while the member net position is 0 at the settlement nothing is booked, on the member or on any client sub-position, whatever the sub-positions hold. Null with no mark." },
            "predictedFundingPerUnit": { "type": "string", "nullable": true, "example": "7.8", "description": "The same display figure at predictedFundingRate, rounded the same way (2.40.0). Omitted whenever predictedFundingRate is." },
            "fundingIntervalHours": { "type": "integer", "format": "int64", "example": 8, "description": "The period the rate applies over: hours between anchors on GRID, 24 on LOCAL_DAILY." },
            "settleCcy": { "type": "string", "example": "USD", "description": "Currency funding PAYMENTS are booked in. Settlement is per instrument, so do not assume one currency across markets." },
            "nextFundingTs": { "type": "integer", "format": "int64", "example": 1785484800000 },
            "funding": { "$ref": "#/components/schemas/FundingSchedule" }
          } } } }
        ] } } } } } }
    },
    "/v1/funding/history": {
      "get": { "tags": ["Public market data"], "operationId": "getFundingHistory", "summary": "Settled funding rates, newest first",
        "description": "One row per settled anchor of the market, newest first, from the venue's projections. settleTs is the anchor boundary that was settled (the command time where a market has no grid) and the key from and to filter on; settledTs is the time of the settlement COMMAND, equal to settleTs plus the timer latency in steady state and later than it for an anchor settled after a stale-mark deferral or a venue outage (revision 3.70; OMITTED, never null, on rows recorded before that revision). After a venue outage spanning several anchors you receive one row per missed anchor, each at the last sequenced rate and mark, sharing one settledTs. The rate fields are the same forms as GET /v1/funding/current: fundingRate is a dimensionless fraction per interval, not a currency amount; fundingPerUnit is a display figure, the charge of one qtyStep at the mark the anchor settled at rounded half-even to the micro and divided by the qtyStep, computed when you read the row with the market's listing at that moment (stated since 2.40.0). REPRODUCING A CHARGE (2.40.0, Member API revision 3.83, section 7): fundingRate and markPrice are stored as settled and never change; the booked charge is netQty x markPrice x contractMultiplier x fundingRate rounded half-even to the micro, on the member net position and on each client sub-position, the member charge minus the sum of the client charges added to the sub-position with the largest absolute netQty; while the member net position is 0 at the settlement (on a LOCAL_DAILY market at the snapshot) nothing is booked, on the member or on any client sub-position, whatever the sub-positions hold. On a LOCAL_DAILY row markPrice is the mean rounded half-even to the tick, the rate computed from the unrounded mean. LOCAL_DAILY rows (revision 3.42) additionally carry the methodology figures settlementValue, indexAtSnapshot, snapshotsUsed and snapshotTs, OMITTED on GRID rows. SKIPPED DAYS ON REQUEST (revision 3.70): a LOCAL_DAILY day the venue did not settle (no position snapshot held, or no mark recorded in the window) is omitted from the default list, no funding is exchanged for it and it is never charged at a later settlement; with includeSkips=true the day is returned as a row with skipped true, skipReason (NO_POSITION_SNAPSHOT, NO_MARK_SNAPSHOTS; an open set), settleTs and snapshotTs, and no rate, mark or methodology field. The default list never carries a skipped row and no settled row carries a skipped property. Public: no signature.",
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "from", "in": "query", "description": "Earliest settleTs, Unix ms, inclusive.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "to", "in": "query", "description": "Latest settleTs, Unix ms, inclusive.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "limit", "in": "query", "description": "Bounds the list, skipped rows included when includeSkips is true.", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 }, "example": 100 },
          { "name": "includeSkips", "in": "query", "description": "true returns the skipped LOCAL_DAILY days as rows with skipped true interleaved with the settled rows, newest first (revision 3.70); the default list never carries them. GRID markets never skip a day.", "schema": { "type": "boolean", "default": false }, "example": false }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": {
            "settleTs": { "type": "integer", "format": "int64", "example": 1785484800000, "description": "The anchor boundary settled, Unix ms (the command time where the market has no grid)." },
            "settledTs": { "type": "integer", "format": "int64", "example": 1785484800412, "description": "The time of the settlement command, Unix ms: equal to settleTs plus the timer latency in steady state, later than it for an anchor settled after a stale-mark deferral or a venue outage. OMITTED (not null) on rows recorded before revision 3.70." },
            "fundingRate": { "type": "string", "example": "0.0001", "description": "The rate charged at that settlement, a dimensionless fraction of notional per interval, not a currency amount." },
            "fundingRatePct": { "type": "string", "nullable": true, "example": "0.01", "description": "fundingRate as a percentage: the same number scaled by 100." },
            "fundingRateAnnualizedPct": { "type": "string", "nullable": true, "example": "10.95", "description": "rate x (365 days / period) x 100, simple, no compounding." },
            "fundingPerUnit": { "type": "string", "nullable": true, "example": "6.5", "description": "A DISPLAY figure, not the figure to multiply (stated since 2.40.0, Member API revision 3.83, section 7; nothing changed): the charge of ONE qtyStep (one lot) at the mark the anchor settled at, rounded half-even to the micro of settleCcy, divided by the qtyStep, and computed when you read the row with the market's listing at that moment (OMITTED where the stored markPrice is not on that listing's grid). Reproduce a booked charge from fundingRate and markPrice instead (the route description)." },
            "markPrice": { "type": "string", "example": "65000", "description": "The mark the anchor settled at." },
            "settleCcy": { "type": "string", "example": "USD", "description": "Currency funding PAYMENTS are booked in." },
            "settlementValue": { "type": "string", "example": "2405.5", "description": "LOCAL_DAILY rows only: the mean of the one-minute marks the day settled at. OMITTED on GRID rows." },
            "indexAtSnapshot": { "type": "string", "example": "2404.9", "description": "LOCAL_DAILY rows only: the index at the position snapshot. OMITTED on GRID rows." },
            "snapshotsUsed": { "type": "integer", "example": 5, "description": "LOCAL_DAILY rows only: the number of one-minute marks in the mean. OMITTED on GRID rows." },
            "snapshotTs": { "type": "integer", "format": "int64", "example": 1785484620000, "description": "LOCAL_DAILY rows only: the scheduled position snapshot instant, Unix ms; on a skipped row the snapshot instant the venue did not capture. OMITTED on GRID rows." },
            "skipped": { "type": "boolean", "example": true, "description": "Present, and true, ONLY on a skipped-day row returned under includeSkips=true (revision 3.70): the venue settled no funding for that LOCAL_DAILY day and never will. A settled row carries no skipped property at all." },
            "skipReason": { "type": "string", "example": "NO_POSITION_SNAPSHOT", "description": "Skipped-day rows only: why the day was not settled. NO_POSITION_SNAPSHOT (no position snapshot was held at the window end, an outage across the snapshot time) or NO_MARK_SNAPSHOTS (no mark was recorded inside the VWAP window). An OPEN set: treat an unknown value as a new reason, not a parser error." }
          } } } } }
        ] } } } },
          "400": { "description": "Unknown symbol (2001); a missing symbol, or a value that does not parse as its type (includeSkips other than true or false, a from, to or limit that is not an integer), answers 5003 with a msg naming the parameter (since 2.37.0; before, that 400 had an empty body).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } } } }
    },
    "/v1/insurance-fund": {
      "get": { "tags": ["Public market data"], "operationId": "getInsuranceFund", "summary": "Insurance fund state",
        "description": "This venue is operated as a pure MTF and runs NO insurance fund, so enabled is false and every currency balance is 0. A defaulter's residual after auto-deleveraging books to the venue, not to a mutualized fund.",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "object", "properties": {
            "enabled": { "type": "boolean", "example": false, "description": "Whether a mutualized insurance fund is in effect. Always false on this MTF." },
            "funds": { "type": "array", "items": { "type": "object", "properties": {
              "ccy": { "type": "string", "example": "USD" },
              "balance": { "type": "string", "example": "0" }
            } }, "description": "One row per settlement currency; every balance is 0 while the fund is disabled." }
          } } } }
        ] } } } } } }
    },
    "/v1/orders": {
      "post": {
        "tags": ["Trading"], "operationId": "placeOrder", "summary": "Place an order",
        "description": "The prefilled body is a minimal limit order that executes against the listings as they stand. It is a LIVE order: sent as it is it rests on the BTC-USD-PERP book below the market until you cancel it (DELETE /v1/orders/{orderId}), and it fills if the market comes down to it. The dropdown above the body carries the other shapes; each one states what it needs. Change clOrdId before every send: repeating one with an identical payload returns the original order with duplicate true rather than placing a second, and repeating it with a changed payload rejects with 2009.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/PlaceOrderRequest" },
          "examples": {
            "limitResting": {
              "summary": "1. Limit order that rests (executes today)",
              "description": "The minimal complete order: symbol, side, type, tif, price, qty, your own reference and your end-client tag, and nothing else. qty 0.001 is on BTC-USD-PERP's 0.0001 qtyStep grid, price 69000 is on its 0.5 tickSize grid, and 69 USD of notional clears the 5 USD minNotional floor and sits far below the 10000000 USD per-order cap. The price is set below the mark observed when this revision was published so the order rests as a maker; a limit price further than the instrument's priceBandBps from the current mark rejects with 2003, so if BTC has moved read GET /v1/mark-price?symbol=BTC-USD-PERP and move the price with it.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.001", "clOrdId": "my-order-1", "clientUid": "CLIENT-A" }
            },
            "marketOrder": {
              "summary": "2. Market order (needs resting liquidity, and OPENS A POSITION)",
              "description": "A market order carries no price: the venue prices it against the book and collars it at marketMaxSlippageBps from the mark (a price sent anyway is accepted and ignored, which is why the field is omitted here). Use tif IOC or FOK; POST_ONLY and GTD are rejected with 2013 on a market order. THIS IS THE ONE ORDER EXAMPLE WHOSE OUTCOME THE VENUE CANNOT PROMISE: a market order needs someone else's order resting on the opposite side, and with nothing to trade against it comes back status REJECTED with rejectCode 2007 (no liquidity) rather than an error envelope, so check GET /v1/orderbook?symbol=BTC-USD-PERP for a non-empty asks side before you send it. When there is an offer to lift, this body TRADES and leaves you long 0.001 BTC, which you carry until you close it (see example 5). For the minNotional floor and the per-order notional cap a market order is valued at the CURRENT mark, not at a limit price.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "MARKET", "tif": "IOC", "qty": "0.001", "clOrdId": "my-order-2", "clientUid": "CLIENT-A" }
            },
            "gtdWithExpiry": {
              "summary": "3. Good-til-date order (needs a future expireTs)",
              "description": "expireTs applies to tif GTD and only to tif GTD. It is an absolute Unix millisecond timestamp and it must be in the future when the venue sequences the order: a past or equal value rejects with 2013. The value below is a deliberately far-future placeholder so that this example does not quietly expire; replace it with the expiry you actually want. Putting expireTs on a GTC order is accepted and recorded but never expires anything. From expireTs on a GTD order never trades (2.43.0, Member API 3.86, from the matching engine's replay-contract line for that release).",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTD", "expireTs": 1893456000000, "price": "69000", "qty": "0.001", "clOrdId": "my-order-3", "clientUid": "CLIENT-A" }
            },
            "stopLimitConditional": {
              "summary": "4. Stop-limit conditional (executes today, rests as PENDING_TRIGGER)",
              "description": "The trigger block belongs to the four conditional types (STOP_MARKET, STOP_LIMIT, TAKE_PROFIT_MARKET, TAKE_PROFIT_LIMIT) and ONLY to those: sending it on a plain LIMIT or MARKET rejects with 2013, because the type field selects the order type, not the presence of a trigger. A conditional carries no top-level price; limitPrice is the price it works at once armed, and it is what the minNotional floor and the per-order cap are measured against. The order is accepted with status PENDING_TRIGGER and is visible under GET /v1/orders/open until it arms or you cancel it.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "STOP_LIMIT", "tif": "GTC", "qty": "0.001", "clOrdId": "my-order-4", "clientUid": "CLIENT-A", "trigger": { "source": "MARK", "price": "72000", "direction": "AT_OR_ABOVE", "limitPrice": "72200" } }
            },
            "reduceOnlyClose": {
              "summary": "5. Reduce-only close (needs an open position)",
              "description": "reduceOnly orders can only ever shrink an existing position, so this body needs you to be LONG BTC-USD-PERP first; with no position, or on the wrong side, it rejects. reduceOnly is perps only and rejects with 2016 on spot. Two asymmetries worth knowing: a reduce-only order within your reducible position is exempt from the minNotional floor, so a sub-floor residual can always be closed, but it is NOT exempt from the per-order notional cap, so closing a large position may take several orders.",
              "value": { "symbol": "BTC-USD-PERP", "side": "SELL", "type": "LIMIT", "tif": "GTC", "price": "71000", "qty": "0.001", "reduceOnly": true, "clOrdId": "my-order-5", "clientUid": "CLIENT-A" }
            },
            "quoteCcyAssertion": {
              "summary": "6. Quote-currency assertion (executes today)",
              "description": "quoteCcy is an assert-and-echo field: the venue checks the currency you believe you are trading in against the instrument, rejects with 2018 on a mismatch and echoes the value on the ack. It never changes how the order is handled. Every instrument listed today is quoted in USD, so this assertion holds venue-wide.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.001", "clOrdId": "my-order-6", "clientUid": "CLIENT-A", "quoteCcy": "USD" }
            },
            "leverageAssertion": {
              "summary": "7. Leverage assertion (FIXED-leverage instruments ONLY, none listed today)",
              "description": "THIS BODY DOES NOT EXECUTE ON ANY CURRENT LISTING and is here to document the shape. A leverage assertion is only ever accepted where the instrument runs a single open-ended risk tier at an exact reciprocal initial-margin rate, which is exactly the instrument that publishes leverageMode FIXED and a non-null maxLeverage on GET /v1/instruments. Every perpetual listed today is TIERED (BTC-USD-PERP, for instance, charges 2 percent initial margin to 1000000 USD of notional, 5 percent to 5000000 and 10 percent above that), so the effective leverage depends on position size, no whole number can be true, maxLeverage is published as null and ANY value here rejects with 2018. Read leverageMode from GET /v1/instruments before sending this field; omitting it is always safe and never changes margin.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.001", "clOrdId": "my-order-7", "clientUid": "CLIENT-A", "leverage": 10 }
            },
            "regulatoryFields": {
              "summary": "8. Regulatory fields (needs YOUR venue-issued Trader ID)",
              "description": "REPLACE EVERY IDENTIFIER BELOW BEFORE SENDING. traderId must be the venue-issued Trader ID of one of your own registered Authorised Users: once your member has registered any, an order without a valid one rejects with 2021, and until then whatever you send is recorded verbatim on the regulatory record, so a placeholder copied from this page becomes a false entry in your own RTS 24 audit trail. The remaining fields are recorded as sent.",
              "value": { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.001", "clOrdId": "my-order-8", "clientUid": "CLIENT-A", "reg": { "traderId": "TR-12-9F3A21BC", "tradingCapacity": "MTCH", "clientIdType": "LEI", "clientId": "529900T8BM49AURSDO55", "investmentDecisionId": "ALGO-7", "executionDecisionId": "TRADER-3", "dea": false, "liquidityProvision": false } }
            }
          }
        } } },
        "responses": {
          "200": { "description": "Synchronous outcome: final status plus any executions produced while matching. The order is durably journaled before you receive this. An engine-level reject still answers 200 with data.status REJECTED and data.rejectCode set.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } }
            ] } } } },
          "400": { "description": "Validation rejects include price or qty off the tickSize/qtyStep grid (2002), notional below the instrument's minNotional (2028), unknown field (2017), assertion mismatch (2018), duplicate clOrdId with different payload (2009), reserved KX- clOrdId (2020), order entry on an RFQ-mode market (2022: no book, trade via POST /v1/rfq), venue end-client identifier capacity reached for a clientUid the venue has never seen (2029), instrument halted (3003), no mark price yet (3005), instrument delisted (3006); a GRID perpetual whose funding catch-up is pending gives 3014 (retry after the settlement lands: the next FUNDING_SETTLED event, or GET /v1/funding/current nextFundingTs in the future; reduce-only orders stay admitted)." },
          "429": { "description": "Rate limit (1003) or order-to-trade regime (1004)." },
          "503": { "description": "Since 2.40.0 documented (served before): engine busy (5001), or 5030 with leaderId and leader on a clustered deployment's node that is not the leader, answered before the route runs and never forwarded; leader is the environment's published entry host, so send the request again there on a new connection with the same clOrdId. A SINGLE write answered 5001 while its node lost the leadership may already be in the venue's log and may still execute on the new leader: read it back by clOrdId on the leader before resubmitting (Member API revision 3.83, section 10.7). Branch on code, never on HTTP 503 alone." }
        }
      },
      "delete": {
        "tags": ["Trading"], "operationId": "cancelOrders", "summary": "Cancel by clOrdId, or cancel all (optionally per symbol and side)",
        "description": "THIS IS A MASS CANCEL WHENEVER clOrdId IS ABSENT. With clOrdId, sent alone, it cancels that one order. Without it, it cancels every open order matching symbol and side, and with neither it cancels every open order you have, on every symbol, including untriggered conditionals. The symbol parameter is prefilled here only to keep an accidental send narrow; clear it deliberately if you mean the whole book. The route reads the three query parameters below and NOTHING ELSE (2.41.0, Member API revision 3.84): a query parameter it does not define (clientUid, orderId, a misspelling), a parameter given twice, a side other than BUY or SELL (an empty one included) or clOrdId with symbol or side answers 400 with code 5003 and a msg naming the parameter, a request body answers 400 with code 2017, and nothing is cancelled; before 2.41.0, without clOrdId, each of these was ignored or widened the filter and the request cancelled every open order the remaining filters matched (a repeated symbol answered 2001), and with clOrdId at most that one order was cancelled. Parameter names match without regard to case. There is no clientUid filter: cancel one end client's orders by orderId with POST /v1/orders/batch/cancel. Only /v1/orders without a trailing slash is this operation: DELETE /v1/orders/, with or without a query, is cancelOrder with an empty orderId and answers 400 with code 5003, nothing cancelled (2.41.0); before, it was this mass cancel. The response reports the count cancelled. Cancels are never rate limited. Since 2.38.0 (Member API revision 3.74) a cancel here, by clOrdId or all, counts one order message on your account-wide order-to-trade ratio, as every other cancel already did; that ratio never blocks.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "clOrdId", "in": "query", "schema": { "type": "string" },
            "description": "Your reference for a single order. Supply it alone to cancel exactly one order (with symbol or side beside it the request is refused 5003, since 2.41.0); omit it and this becomes a mass cancel." },
          { "name": "symbol", "in": "query", "schema": { "type": "string" }, "example": "BTC-USD-PERP",
            "description": "Limits a mass cancel to one instrument. Omit to cancel across every instrument. An unknown or empty symbol answers 2001." },
          { "name": "side", "in": "query", "schema": { "type": "string", "enum": ["BUY", "SELL"] },
            "description": "Limits a mass cancel to one side, BUY or SELL in any case. Since 2.41.0 any other value, an empty one included, answers 5003 with nothing cancelled; before, it was no filter and the cancel covered both sides." }
        ],
        "responses": { "200": { "description": "OK. data.canceled is the number of orders cancelled; cancelling by clOrdId returns the cancelled order instead.",
          "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "oneOf": [
              { "$ref": "#/components/schemas/Order" },
              { "type": "object", "properties": { "canceled": { "type": "integer", "example": 3, "description": "Number of orders cancelled by a mass cancel." } } }
            ], "description": "The cancelled Order when clOrdId was supplied; the count object on a mass cancel." } } }
          ] } } } },
          "400": { "description": "Nothing was cancelled. 5003 (since 2.41.0): a query parameter other than clOrdId, symbol and side, a parameter given twice, a side other than BUY or SELL, or clOrdId with symbol or side; msg names the parameter and ends 'nothing was cancelled'; also the path /v1/orders/ with a trailing slash, an empty orderId (cancelOrder). 2017 (since 2.41.0): a request body (this route takes none). 2001: an unknown or empty symbol." },
          "404": { "description": "2014: clOrdId names no open order of yours." },
          "503": { "description": "Since 2.40.0 documented (served before): engine busy (5001), or 5030 with leaderId and leader on a clustered deployment's node that is not the leader, answered before the route runs and never forwarded; leader is the environment's published entry host, so send the request again there on a new connection with the same clOrdId. A SINGLE write answered 5001 while its node lost the leadership may already be in the venue's log and may still execute on the new leader: read it back by clOrdId on the leader before resubmitting (Member API revision 3.83, section 10.7). Branch on code, never on HTTP 503 alone." } }
      }
    },
    "/v1/orders/batch": {
      "post": {
        "tags": ["Trading"], "operationId": "placeOrderBatch", "summary": "Place up to 50 independent orders in one message",
        "description": "One signed message, N client-tagged orders (the mass-close use case: one message, N reduceOnly closes each tagged with its own clientUid). NON-ATOMIC BY DESIGN: each entry validates and executes independently, exactly like a single POST /v1/orders, and one entry's rejection never touches its neighbours. Entries are submitted to the matching engine in array order (array order is engine sequence order among the batch; other members' traffic may interleave between entries). The response is code 0 with data.results in array order, HTTP 200 even when every entry failed: a successful entry has the same shape as the single-order place response data (engine-level rejects such as 2028 ride that payload as rejectCode, exactly like the single route); a failure entry is { code, msg, clOrdId }: a refusal of the gateway (strict fields and wrong-typed values 2017, reserved KX- namespace 2020, grid misalignment 2002, and so on), the matching engine's 2009 (duplicate clOrdId with a different payload), 5001 for an entry the venue did not accept (after an entry the venue's intake refused as it was submitted, every later entry answers 5001 \"not submitted\"; on a clustered deployment the replicated intake can refuse an entry after the later ones were submitted, which may then take effect: read every row) and, since 2.38.0, 5000 for an entry whose outcome the venue could not confirm, where such a fault answered the whole request with an undocumented 500: reconcile a 5000 row by its clOrdId and resend it only with the SAME clOrdId. Entry member names are case-sensitive, where the single POST /v1/orders body is not. Rate limits: the batch consumes one order-budget unit PER ENTRY, charged up front, all or nothing: if fewer than N units are available the whole batch answers 1003 with retryAfterMs and consumes nothing. Every entry also counts as one order message under the order-to-trade regime. Envelope-level errors are limited to authentication, the read-only credential (1005), throttle (1003), malformed body or entry count (2002), the engine-busy shed (5001), the order-to-trade block (1004) and 5030 on a clustered deployment's follower node; the 5001 and the 1004 come after the charge, so the N units stay spent. Also available on the private WebSocket as op orders.batch with identical body and results. Not offered over FIX: FIX members submit singles.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/BatchPlaceRequest" },
          "examples": {
            "twoRestingOrders": {
              "summary": "1. Two independent resting orders (executes today)",
              "description": "Two complete orders across two instruments, each with its own clOrdId and its own clientUid, showing that entries are independent rather than legs of one strategy. Both are on their instrument's grids: BTC-USD-PERP takes 0.0001 qty steps and 0.5 ticks, ETH-USD-PERP takes 0.001 qty steps and 0.05 ticks. Both prices sit on the passive side of the mark observed when this revision was published, so both rest as makers and both stay on the book until you cancel them; if either market has moved read GET /v1/ticker and move the price with it, or the entry rejects with 2003. Every clOrdId in a batch must be distinct: two entries sharing one reference is the 2009 case.",
              "value": { "orders": [
                { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.001", "clOrdId": "my-batch-1a", "clientUid": "CLIENT-A" },
                { "symbol": "ETH-USD-PERP", "side": "SELL", "type": "LIMIT", "tif": "GTC", "price": "3450", "qty": "0.05", "clOrdId": "my-batch-1b", "clientUid": "CLIENT-B" }
              ] }
            },
            "massClose": {
              "summary": "2. Mass close, one message per end client (needs open positions)",
              "description": "The use case the route exists for: one signed message carrying N reduceOnly closes, each tagged with the end client it belongs to. It needs you to already be LONG both instruments; entries that have nothing to reduce reject individually and leave their neighbours untouched, which is the whole point of a non-atomic batch. Remember the deliberate asymmetry: reduce-only entries are exempt from the minNotional floor but not from the per-order notional cap, so a large position closes in several entries.",
              "value": { "orders": [
                { "symbol": "BTC-USD-PERP", "side": "SELL", "type": "LIMIT", "tif": "GTC", "price": "71000", "qty": "0.001", "reduceOnly": true, "clOrdId": "my-batch-2a", "clientUid": "CLIENT-A" },
                { "symbol": "ETH-USD-PERP", "side": "SELL", "type": "LIMIT", "tif": "GTC", "price": "3450", "qty": "0.05", "reduceOnly": true, "clOrdId": "my-batch-2b", "clientUid": "CLIENT-B" }
              ] }
            }
          }
        } } },
        "responses": {
          "200": { "description": "data.results: one entry per order, array order preserved, mixed outcomes expected. Every executed entry is durably journaled before you receive this.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "results": { "type": "array", "items": { "anyOf": [
                  { "$ref": "#/components/schemas/Order" },
                  { "$ref": "#/components/schemas/BatchEntryError" }
                ] }, "description": "Array order preserved. A row carrying code is a failure row (BatchEntryError); any other row is the Order the entry produced (engine rejects ride rejectCode). anyOf, not oneOf: Order declares no required member, so every failure row also validates as an Order and the code member decides." }
              } } } }
            ] } } } },
          "400": { "description": "Malformed batch body or entry count outside 1 to 50 (2002 with a descriptive msg)." },
          "403": { "description": "Read-only credential (1005)." },
          "429": { "description": "Rate limit (1003: fewer than N order-budget units available, nothing consumed, retryAfterMs covers the full deficit) or order-to-trade regime block (1004, after the charge)." },
          "503": { "description": "Engine busy (5001, after the charge: the N units stay spent), or 5030 with leaderId and leader on a clustered deployment's follower node." }
        }
      }
    },
    "/v1/orders/batch/amend": {
      "post": {
        "tags": ["Trading"], "operationId": "amendOrderBatch", "summary": "Amend up to 50 of your orders in one message",
        "description": "2.38.0 (Member API revision 3.74, section 6c). Each entry { orderId, price?, qty? } the venue submits reaches the matching engine as the ORDINARY amendment of PUT /v1/orders/{orderId}: qty is the new TOTAL quantity, a quantity decrease at the same price keeps queue priority, any price change or quantity increase is cancel and new, and every engine check of the single amendment applies at the current state. NON-ATOMIC BY DESIGN: entries reach the engine in array order, other members' traffic may interleave, and a refused entry never stops a later one, so send an entry that depends on another's outcome in a second message. Entry member names are case-sensitive and a wrong JSON type answers 2017; an order named by two entries: the first runs, every later one answers 2013. The response is code 0 with data.results in array order, HTTP 200 even when every entry failed: a row carrying code is a BatchTargetError; any other row is the Order as of the response's asOfSeq (the PUT data; when the venue could not read the orders back after the batch, the order's last state change among the batch's entries, every row then the order as of asOfSeq or later), which can read REJECTED (2005, a post-only order repriced to cross; 2015 under REJECT_TAKER) or CANCELED (STP_CANCEL): that level is gone, place it again. Rate limits: one order-budget unit PER ENTRY, charged up front, all or nothing, after the engine-busy check (1003 and an engine-busy 5001 consume nothing; the units of a batch whose entries are refused afterwards stay spent). Order-to-trade: an entry on a market where the regime blocks you answers a 1004 row and the other entries run; an entry counts as one order message when the venue hands it to the engine. Envelope errors come only before anything is submitted: 1001, 1005, 2002, 2034 (production), 1003, 5001 (the shed, or the orders could not be looked up) and 5030 on a follower node. Also the private WebSocket op orders.batchAmend, whose ack carries asOfSeq. Not offered over FIX. The venue may withdraw the route during an incident; it then answers 404 as before 2.38.0.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/BatchAmendRequest" },
          "examples": {
            "resizeAndReprice": {
              "summary": "1. Resize and reprice two of your resting orders (needs your open orderIds)",
              "description": "REPLACE BOTH orderIds BEFORE SENDING: take them from GET /v1/orders/open. An orderId that is not one of your open orders answers a 2014 row and nothing is submitted for it. The first entry sizes an order DOWN at its price, which keeps its queue priority; the second reprices an order, which is cancel and new (fresh priority, re-matched as a taker). 0.0005 is on BTC-USD-PERP's 0.0001 qtyStep grid and 68500 on its 0.5 tick grid; a price farther than priceBandBps from the current mark answers 2003, and a post-only order repriced to cross comes back REJECTED 2005.",
              "value": { "amends": [
                { "orderId": 887731, "qty": "0.0005" },
                { "orderId": 887732, "price": "68500" }
              ] }
            },
            "orderedShift": {
              "summary": "2. Shift a two-sided quote up, asks first (needs your open orderIds)",
              "description": "REPLACE THE orderIds BEFORE SENDING with the ask and the bid of your quote from GET /v1/orders/open (an orderId that is not one of your open orders answers a 2014 row). Entries reach the engine in array order and a repriced order re-matches as a taker, so in a shift up amend the ask before the bid (the side moving away from the other first): a bid moved first to or through your own resting ask meets it under your self-trade policy. The advice holds only when the earlier entry takes effect: a refused ask entry leaves the bid entry to cross it.",
              "value": { "amends": [
                { "orderId": 887742, "price": "69600" },
                { "orderId": 887741, "price": "69400" }
              ] }
            }
          }
        } } },
        "responses": {
          "200": { "description": "data.results: one row per entry, array order preserved, mixed outcomes expected. Every amendment that took effect is durably journaled before you receive this; asOfSeq is at or after every entry.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "results": { "type": "array", "items": { "anyOf": [
                  { "$ref": "#/components/schemas/Order" },
                  { "$ref": "#/components/schemas/BatchTargetError" }
                ] }, "description": "Array order preserved. A row carrying code is a failure row (BatchTargetError); any other row is the Order, whose status says whether it still stands (rejectCode 5005 on a NEW or PARTIALLY_FILLED row: the amendment took effect before a contained fault)." }
              } } } }
            ] } } } },
          "400": { "description": "Malformed batch body, a member beside amends, or an entry count outside 1 to 50 (2002 with a descriptive msg)." },
          "403": { "description": "Read-only credential (1005), or on a production venue no licensing profile configured for your member (2034)." },
          "429": { "description": "Rate limit (1003): fewer than N order-budget units available, nothing consumed, retryAfterMs covers the full deficit." },
          "503": { "description": "Engine busy (5001: the venue sheds, nothing charged; or the orders could not be looked up, nothing submitted and the N units spent), or 5030 with leaderId and leader on a clustered deployment's follower node." }
        }
      }
    },
    "/v1/orders/batch/cancel": {
      "post": {
        "tags": ["Trading"], "operationId": "cancelOrderBatch", "summary": "Cancel up to 50 of your orders in one message",
        "description": "2.38.0 (Member API revision 3.74, section 6c). Each entry names one of your orders by orderId OR clOrdId, exactly one. The venue first looks every entry up: an entry naming no open order of yours (not found, not yours, terminal, or a reference naming no open order) answers a 2014 row and nothing is submitted for it; every other entry reaches the matching engine as the ORDINARY cancel of DELETE /v1/orders/{orderId}, in array order, never refused by a halt, a suspension, a risk state or a session measure. An order named twice (by orderId and by clOrdId included) answers 2013 on the later entry. FREE: no order-budget unit, never throttled, never blocked by the order-to-trade regime (each submitted entry counts one order message on your account-wide ratio, each cancelled order one on its market). One cancellation batch of yours is processed at a time on a venue node, a later one waits for it; 5001 when the venue's intake is nearly full or eight of your cancellation batches already wait (your single cancels and cancel-all are never held). The response is code 0 with data.results in array order: the cancelled Order (the single cancel's data), or a BatchTargetError. Envelope errors come only before anything is submitted: 1001, 1005, 2002, 5001 and 5030 on a follower node. Also the private WebSocket op orders.batchCancel, whose ack carries asOfSeq. Not offered over FIX. The venue may withdraw the route during an incident; it then answers 404 as before 2.38.0.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/BatchCancelRequest" },
          "examples": {
            "byIdAndByReference": {
              "summary": "1. Cancel two resting orders, one by orderId and one by clOrdId (needs open orders)",
              "description": "REPLACE THE orderId AND THE clOrdId BEFORE SENDING: take them from GET /v1/orders/open. An entry naming no open order of yours answers a 2014 row and nothing is journaled for it. Each entry names its order by exactly one identifier.",
              "value": { "cancels": [
                { "orderId": 887734 },
                { "clOrdId": "my-order-1" }
              ] }
            }
          }
        } } },
        "responses": {
          "200": { "description": "data.results: one row per entry, array order preserved. Every cancel that took effect is durably journaled before you receive this; asOfSeq is the highest seqNo of the entries submitted, else the lookup's.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "results": { "type": "array", "items": { "anyOf": [
                  { "$ref": "#/components/schemas/Order" },
                  { "$ref": "#/components/schemas/BatchTargetError" }
                ] }, "description": "Array order preserved. A row carrying code is a failure row (BatchTargetError); any other row is the cancelled Order (status CANCELED, cancelReason USER_REQUESTED; rejectCode 5005 when the cancel took effect before a contained fault)." }
              } } } }
            ] } } } },
          "400": { "description": "Malformed batch body, a member beside cancels, or an entry count outside 1 to 50 (2002 with a descriptive msg)." },
          "403": { "description": "Read-only credential (1005)." },
          "503": { "description": "Engine busy (5001: the venue's intake is nearly full, the orders could not be looked up, or eight of your cancellation batches already wait on the node; nothing submitted), or 5030 with leaderId and leader on a clustered deployment's follower node." }
        }
      }
    },
    "/v1/orders/{orderId}": {
      "get": {
        "tags": ["Trading"], "operationId": "getOrder", "summary": "Order state by venue order id",
        "description": "Takes the venue orderId returned on the place ack or listed by GET /v1/orders/open; there is no default. To look an order up by your own reference instead, use the clOrdId echoed on every response for it.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "The venue order id, from a place ack or GET /v1/orders/open." }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } }
          ] } } } },
          "404": { "description": "Unknown order, or not yours (2014)." } }
      },
      "put": {
        "tags": ["Trading"], "operationId": "amendOrder", "summary": "Amend price and/or quantity",
        "description": "NEEDS ONE OF YOUR OWN WORKING ORDERS: orderId is a path parameter with no default, so take one from GET /v1/orders/open (or from the ack of an order you just placed) before sending. A quantity decrease at the same price keeps queue priority; any price change or quantity increase is processed as cancel and new, and outside a call auction the re-match treats the order as a new one: a post-only order that would cross is rejected 2005 and removed, and your self-trade policy applies against your own resting orders; these answer inside the 200 with status REJECTED or CANCELED (Member API section 6, Manage orders); during a call auction the repriced order rests. The FULL amended quantity is re-checked against the instrument's minNotional at the effective price (2028 below it); grid misalignment rejects with 2002 and a price outside the band with 2003. An amendment consumes one order-budget unit exactly like a placement or a batch entry (1003 when exhausted) and counts as an order message under the order-to-trade regime (1004); cancels are never throttled.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "The venue order id of one of your own working orders, from GET /v1/orders/open." }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/AmendOrderRequest" },
          "examples": {
            "repriceAndResize": {
              "summary": "1. Reprice and resize together",
              "description": "Values matched to the resting limit order example on POST /v1/orders: 68500 is on BTC-USD-PERP's 0.5 tick grid, 0.002 is on its 0.0001 qty grid, and the amended notional of 137 USD clears the 5 USD floor. Because the price changes, this is processed as cancel and new and the order goes to the back of the queue.",
              "value": { "price": "68500", "qty": "0.002" }
            },
            "resizeOnly": {
              "summary": "2. Resize only, keeping queue priority",
              "description": "Omitting price leaves the price as it stands. A quantity DECREASE at an unchanged price is the one amendment that keeps your place in the queue; an increase is still cancel and new.",
              "value": { "qty": "0.002" }
            },
            "repriceOnly": {
              "summary": "3. Reprice only",
              "description": "Omitting qty leaves the quantity as it stands. The full standing quantity is re-checked against minNotional at the new price.",
              "value": { "price": "68500" }
            }
          }
        } } },
        "responses": { "200": { "description": "OK. The amended order in its new state: since 2.40.0 stated (Member API revision 3.83, section 6), the order read just after the amendment (the open order, else its terminal record), so it can already carry a later fill, while the envelope asOfSeq is the amendment's own sequence number.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } }
            ] } } } },
          "404": { "description": "Unknown order, or not yours (2014)." },
          "503": { "description": "Since 2.40.0 documented (served before): engine busy (5001), or 5030 with leaderId and leader on a clustered deployment's node that is not the leader, answered before the route runs and never forwarded; leader is the environment's published entry host, so send the request again there on a new connection with the same clOrdId. A SINGLE write answered 5001 while its node lost the leadership may already be in the venue's log and may still execute on the new leader: read it back by clOrdId on the leader before resubmitting (Member API revision 3.83, section 10.7). Branch on code, never on HTTP 503 alone." } }
      },
      "delete": {
        "tags": ["Trading"], "operationId": "cancelOrder", "summary": "Cancel one order",
        "description": "Cancels exactly one order and nothing else, which is the safe counterpart to the mass cancel on DELETE /v1/orders. Takes the venue orderId from a place ack or GET /v1/orders/open; there is no default. An empty orderId, DELETE /v1/orders/ with a trailing slash (what a path built from this template becomes when the id is empty), answers 400 with code 5003 and cancels nothing (2.41.0); before, that path was the mass cancel of DELETE /v1/orders. Cancels are never rate limited.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "orderId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "The venue order id, from a place ack or GET /v1/orders/open." }],
        "responses": { "200": { "description": "OK. The cancelled order, rendered from the cancel event (status CANCELED, cancelReason USER_REQUESTED, acceptedTs the cancel's time; stated since 2.40.0).",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Order" } } }
            ] } } } },
          "400": { "description": "Nothing was cancelled. 5003 (since 2.41.0): an empty orderId, the path /v1/orders/ with a trailing slash, with or without a query; msg 'orderId is empty: ...; nothing was cancelled'." },
          "404": { "description": "Unknown order, or not yours (2014)." },
          "503": { "description": "Since 2.40.0 documented (served before): engine busy (5001), or 5030 with leaderId and leader on a clustered deployment's node that is not the leader, answered before the route runs and never forwarded; leader is the environment's published entry host, so send the request again there on a new connection with the same clOrdId. A SINGLE write answered 5001 while its node lost the leadership may already be in the venue's log and may still execute on the new leader: read it back by clOrdId on the leader before resubmitting (Member API revision 3.83, section 10.7). Branch on code, never on HTTP 503 alone." } }
      }
    },
    "/v1/orders/open": {
      "get": {
        "tags": ["Trading"], "operationId": "getOpenOrders", "summary": "Open orders, including untriggered conditionals",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "symbol", "in": "query", "schema": { "type": "string" } }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Order" } } } }
        ] } } } } }
      }
    },
    "/v1/orders/history": {
      "get": {
        "tags": ["Trading"], "operationId": "getOrdersHistory", "summary": "Closed orders and rejections, newest first",
        "description": "Closed orders AND rejections: the only place a rejection that never reached the book can be re-read after the fact, which makes it the right source for a daily reconciliation of everything you sent. Served from the projection store, so the envelope asOfSeq is the store watermark, not the engine head. Rows carry the optional hedge-mode positionSide exactly like the live order surfaces: LONG or SHORT, OMITTED (not null) on netting orders.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" } },
          { "name": "from", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, inclusive lower bound on acceptedTs (the first acceptance, on a REJECTED row the rejection time; OrderHistoryRow)." },
          { "name": "to", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, inclusive upper bound on acceptedTs (the first acceptance, on a REJECTED row the rejection time; OrderHistoryRow)." },
          { "name": "limit", "in": "query", "schema": { "type": "integer" }, "example": 100, "description": "Default 100, clamped to 1 to 1000." }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/OrderHistoryRow" } } } }
        ] } } } },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); nothing changed on your account." } }
      }
    },
    "/v1/executions": {
      "get": {
        "tags": ["Trading"], "operationId": "getExecutions", "summary": "Your recent executions with fees, role, flags, clOrdId, refSource and clientUid",
        "description": "Every row carries your own side's clOrdId and refSource MEMBER. Venue-initiated closes carry a venue-generated reference instead: KX-LQ-{orderId} on a liquidation slice, KX-ADL-{tradeId} on an ADL close, both with refSource VENUE. Served from the venue's history store, so the envelope asOfSeq is the store watermark; since 2.40.0 (Member API revision 3.83, a correction in force at publication), while the store has a recorded hole (store.status REPAIRING) the route serves only the executions at or below the watermark, where it could carry rows from after the hole while the hole's own rows were missing.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer" }, "example": 50 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Execution" } } } }
        ] } } } },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); nothing changed on your account." } }
      }
    },
    "/v1/lots": {
      "get": {
        "tags": ["Lots"], "operationId": "getLots", "summary": "Open lots of one clientUid on one instrument, oldest first within each bucket",
        "description": "CFD-style display of an end client's open position as the individual opening fills (lots) that built it, folded on demand from the fill history per (clientUid, hedge bucket, instrument): every bucket-increasing fill opens a lot (lotId = the opening fill's tradeId, entry = its price), reducing fills consume explicitly assigned lots first (see POST /v1/lots/{lotId}/close) and then FIFO from the oldest, and a fill through zero closes everything and opens one opposite-direction lot with the remainder. A display convention only: the engine keeps no lots and margin never reads them. Served from the projection store, so the envelope asOfSeq is the store watermark: a fill acked a moment ago may not be folded yet. The fold is BOUNDED, and the bounds are published so you can predict a crossing: at most 100000 fills per (clientUid, symbol) scope; at most 20000 funding settlements to attribute (about 18 years of an 8 hour grid, counted from the first fill the fold covers); at most 5000000 attribution steps (settlements x lots open at each). Past a bound the request rejects with 2013 and a message naming it. positionSide narrowing folds ONLY that bucket, reducing the attribution work in proportion and starting the settlement count at that bucket's first fill; past the settlements bound, or when a single bucket alone exceeds the work bound, there is no in-API remedy: reconcile that client by positions and executions instead (POST /v1/lots/{lotId}/close is refused for such a scope too).\n\nFUNDING ON LOTS. Each lot carries accFunding, the financing it has been charged since it opened, in settleCcy and signed from the client's side (negative paid). The venue charges funding on the client sub-position NET, once per settlement anchor, never per lot, so the per-lot figure is an ATTRIBUTION of a booked charge and not itself a booked figure. It is exact at each anchor: every anchor charges exactly the lots that were open when it settled, and the shares sum to the charge on the bucket net to the micro (the rounding remainder is booked to the largest lot, the same rule the venue uses across a member's clients). Financing follows the quantity that was actually held, so a partially closed lot keeps what it incurred while it was larger, and a fully closed lot takes its financing with it. That is why the envelope publishes three figures: accFunding is what the venue BOOKED on the sub-position, openLotsFunding is what the lots below carry, and closedLotsFunding is the difference, financing paid by quantity that has since been closed. Reconcile client statements against accFunding, not against the sum of the lots. Funding applies to perpetual markets only; on spot every funding figure here is 0.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "clientUid", "in": "query", "required": true, "schema": { "type": "string" }, "example": "CLIENT-A" },
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "positionSide", "in": "query", "schema": { "type": "string", "enum": ["NET", "LONG", "SHORT"] },
            "description": "Filters to one hedge bucket; omit for the open lots of all three buckets." }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "clientUid": { "type": "string", "example": "CLIENT-A" },
              "symbol": { "type": "string", "example": "BTC-USD-PERP" },
              "mark": { "type": "string", "nullable": true, "example": "69000",
                "description": "The mark the unrealizedPnl figures are measured at; OMITTED while the market has no mark yet (per-lot unrealizedPnl is omitted then too)." },
              "settleCcy": { "type": "string", "example": "USD", "description": "Currency every money figure in this response is expressed in." },
              "accFunding": { "type": "string", "example": "-12.5",
                "description": "AUTHORITATIVE. Lifetime funding the venue BOOKED on this client sub-position, summed over the buckets this response covers, signed from the client's side (negative paid). This is the figure to reconcile a client statement against." },
              "openLotsFunding": { "type": "string", "example": "-9.2",
                "description": "Sum of accFunding over the lots below. Attribution, not a booked figure." },
              "closedLotsFunding": { "type": "string", "example": "-3.3",
                "description": "accFunding minus openLotsFunding: financing already paid by quantity that has since been closed. Non-zero is normal on any client that has ever reduced a position." },
              "lots": { "type": "array", "items": { "$ref": "#/components/schemas/Lot" },
                "description": "Grouped by bucket (NET, then LONG, then SHORT), oldest first WITHIN each bucket, which is that bucket's FIFO consumption order." }
            } } } }
          ] } } } },
          "400": { "description": "Missing clientUid or symbol, an unknown positionSide value, or a fold past one of its bounds (2013: 100000 fills per scope, 20000 funding settlements, or 5000000 attribution steps); unknown symbol (2001)." }
        }
      }
    },
    "/v1/lots/closures": {
      "get": {
        "tags": ["Lots"], "operationId": "getLotClosures", "summary": "Close attribution: every closing fill mapped to the lots it consumed",
        "description": "The close-attribution feed for one clientUid on one instrument, folded from the same fill history as GET /v1/lots and by the same rules, but without the clamp to the live sub-position that GET /v1/lots applies: the one close this feed cannot list is a close the fold cannot attribute (a liquidation on an RFQ-mode market), which GET /v1/lots trims and no row here names (before 2.39.0 this description said the two views could never disagree). Rows are oldest first, and one closing fill that consumed several lots appears as one row per lot in consumption order. This is where a TARGETED close is verified. An assignment is advisory and never rejects: a close that fills after the lot shrank takes what is left of it and sends only the surplus FIFO, a FIX tag 9020 or 9028 target that names no open lot of that client in that bucket sends the whole close FIFO, and an IOC that finds no liquidity closes nothing, so the lot stays open (corrected in 2.39.0: this description said such an IOC degraded to FIFO); this feed states which lots were actually consumed. Venue-initiated closes are included and carry their trade flags, ADL tear-ups among them (sourced from the per-client ADL record, because the ADL trade itself carries no client identifiers). Served from the history store like GET /v1/lots, so the envelope asOfSeq is the store watermark, and bounded by the same fold bounds.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "clientUid", "in": "query", "required": true, "schema": { "type": "string" }, "example": "CLIENT-A" },
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "positionSide", "in": "query", "schema": { "type": "string", "enum": ["NET", "LONG", "SHORT"] },
            "description": "Filters to one hedge bucket; omit for all three." },
          { "name": "from", "in": "query", "schema": { "type": "integer", "format": "int64" },
            "description": "Optional Unix ms lower bound on the closing fill's ts, inclusive." },
          { "name": "to", "in": "query", "schema": { "type": "integer", "format": "int64" },
            "description": "Optional Unix ms upper bound on the closing fill's ts, inclusive." }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "clientUid": { "type": "string", "example": "CLIENT-A" },
              "symbol": { "type": "string", "example": "BTC-USD-PERP" },
              "settleCcy": { "type": "string", "example": "USD", "description": "Currency every money figure in this response is expressed in." },
              "closures": { "type": "array", "items": { "$ref": "#/components/schemas/LotClosure" },
                "description": "Oldest first; one row per (closing fill, lot consumed)." }
            } } } }
          ] } } } },
          "400": { "description": "Missing clientUid or symbol, an unknown positionSide value, a barrier symbol (lots do not exist there), or a fold past one of its bounds (2013); unknown symbol (2001)." }
        }
      }
    },
    "/v1/lots/{lotId}/close": {
      "post": {
        "tags": ["Lots"], "operationId": "closeLot", "summary": "Close one open lot with a market IOC order assigned to it",
        "description": "Resolves the lot at request time and submits a MARKET IOC order on the opposite side for the lot's remaining quantity, tagged with the lot's hedge bucket, recording an assignment so the fold consumes THAT lot first. The response carries the lot as the fold saw it and the ordinary place-order response data for the close, executions included. Races are resolved by the fills, never by the assignment: an IOC that finds no liquidity (order.status REJECTED with rejectCode 2007 on an empty opposite side) leaves the lot open, and a close that fills after the lot shrank folds against what is left. THIS IS ORDER ENTRY: it consumes one order-budget unit, counts under the order-to-trade regime, and requires a trading-capable credential (1005 on a READ_ONLY key).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "lotId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "The lotId from GET /v1/lots, which is the tradeId of the lot's opening fill." }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/CloseLotRequest" },
          "examples": {
            "closeLot": {
              "summary": "1. Close one lot (needs an open lot: take lotId from GET /v1/lots)",
              "description": "The close is a MARKET IOC, so it also needs resting liquidity on the opposite side; with nothing to trade against, the order comes back status REJECTED with rejectCode 2007 and the lot stays open. reduceOnly is deliberately absent here: the default is a plain order under normal margin admission, because the reduce-only budget is member-level (see the CloseLotRequest schema).",
              "value": { "clientUid": "CLIENT-A", "symbol": "BTC-USD-PERP", "clOrdId": "close-lot-1" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "The lot as resolved at request time plus the synchronous outcome of the close order. The order is durably journaled before you receive this; an engine-level reject answers 200 with order.status REJECTED and order.rejectCode set.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "lot": { "$ref": "#/components/schemas/Lot" },
                "order": { "$ref": "#/components/schemas/Order" }
              } } } }
            ] } } } },
          "400": { "description": "Missing clientUid or symbol (2013), unknown field (2017), unknown symbol (2001)." },
          "404": { "description": "No open lot with this lotId for the given clientUid and symbol (2032): never opened, already fully closed, or belonging to a different client." },
          "429": { "description": "Rate limit (1003) or order-to-trade regime (1004)." }
        }
      }
    },
    "/v1/rfq": {
      "post": {
        "tags": ["RFQ"], "operationId": "createRfq", "summary": "Create an RFQ (request liquidity on an RFQ-mode market)",
        "description": "Strict like order entry: an unknown JSON member rejects with 2017. On a BARRIER market the requester is always the HOLDER and barrier terms are required: BUY = long, knocked out at or below the barrier; SELL = short, knocked out at or above. Makers quote the ENTRY price. Holder margin is the entry-to-barrier distance at entry (the capped maximum loss of a stop guaranteed AT the barrier), tracking the remaining distance thereafter; the writer margins like a perp, bounded by the take-profit distance when the request carries barrier.takeProfit (revision 3.43: an optional second exit on the profit side of the entry, at which the contract also terminates AT the level). CLOSE REQUEST (2.23.0): a body carrying closeContractId instead of side / qty / barrier asks the WRITER of one of your open barrier contracts to quote a price at which the contract closes early; only the writer sees and may quote it, its price must lie strictly inside the contract's terms, and your accept closes the contract AT that price (terminationReason EARLY_CLOSE), with maker/taker fees like the entry trade and no margin admission (closing releases margin). The prefilled body creates a REAL request on the open board that other members can quote; it stays live for its quoting window unless you cancel it with POST /v1/rfq/{rfqId}/cancel. Since 2.42.0 (Member API revision 3.85, section 6b) a request is idempotent on its clOrdId like an order: a reference you already used (on an order, a swap take, a request or a quote) answers 2009 and opens nothing, with no restatement of the original and the msg 'clOrdId already used: an RFQ request or quote is never restated, read GET /v1/rfq/mine or GET /v1/rfq/quotes/mine', from the matching engine's replay-contract line for that release.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/RfqCreateRequest" },
          "examples": {
            "barrierOpenEnded": {
              "summary": "1. Open-ended barrier knock-out (needs a market WITHOUT maxContractLifeHours on GET /v1/instruments; every KO market of the tracked sandbox and production listings publishes one, 8784 h)",
              "description": "The minimal barrier request: an open-ended contract, so no barrier.expiryTs at all. Executes only on a market that publishes no maxContractLifeHours on GET /v1/instruments: where the market publishes one (2.35.0), an opening request without barrier.expiryTs is refused 2027, and the dated shape of example 2 is the one to send, with its placeholder expiryTs REPLACED by a value inside the cap (example 2 as served is deliberately not sendable there). BTC-USD-KO sizes on the grid of its perpetual since Member API revision 3.71 (in force on production from genesis and on the sandbox from the re-listing on the date venue operations announce; GET /v1/instruments serves the values in force): qtyStep and minQty 0.0001 BTC on a 0.5 tick grid, minNotional 100 USD valued at the mark on an opening request, at its entry on every quote and at the contract's whole quantity on a close request. qty 1 here is one bitcoin, far above the floor, while the smallest contract of 0.0001 BTC is below it at every mark under 1,000,000 USD, so size a small request with headroom: at a 70,000 USD mark 0.0015 BTC clears the floor and 0.0013 BTC answers 2028. THE ONE VALUE TO CHECK BEFORE SENDING IS THE BARRIER: on a BUY you are the long holder, so the level must be STRICTLY BELOW the current mark or the request rejects with 2027. 60000 was comfortably below the mark when this revision was published, but the mark moves, so read GET /v1/mark-price?symbol=BTC-USD-KO and put the level on the correct side of it.",
              "value": { "symbol": "BTC-USD-KO", "side": "BUY", "qty": "1", "expiresInMs": 120000, "barrier": { "level": "60000" }, "clOrdId": "my-rfq-1", "clientUid": "CLIENT-A" }
            },
            "barrierDated": {
              "summary": "2. Barrier with a contract expiry (REPLACE expiryTs: in the future AND within the market's maxContractLifeHours where it publishes one, 366 days on the listed KO markets; the placeholder here lies beyond that cap)",
              "description": "Adds a dated contract: it settles at mark on the first price tick at or past barrier.expiryTs unless the barrier is touched first. The timestamp must be in the future or the request rejects with 2027, and where the market publishes maxContractLifeHours on GET /v1/instruments (2.35.0, 8784 h on every listed KO market) it must also lie within that many hours of the moment you send, else 2027 as well. The value here is a deliberately far-future placeholder: it never quietly goes stale, it executes on a market without a cap, and under a cap it is NOT sendable, so this example never quietly opens a dated contract; replace it with the expiry you want (the Postman collection's koExpiryTs, thirty days ahead, is a ready value). The barrier caveat from example 1 applies unchanged.",
              "value": { "symbol": "BTC-USD-KO", "side": "BUY", "qty": "1", "expiresInMs": 120000, "barrier": { "level": "60000", "expiryTs": 1893456000000 }, "clOrdId": "my-rfq-2", "clientUid": "CLIENT-A" }
            },
            "barrierWithTakeProfit": {
              "summary": "3. Barrier with a take profit (check BOTH levels against the mark; open-ended like example 1, same maxContractLifeHours condition)",
              "description": "Open-ended like example 1, so it needs a market without maxContractLifeHours or an added barrier.expiryTs inside the cap (2027 otherwise). Adds the optional second exit (revision 3.43): the contract also terminates AT barrier.takeProfit when the mark reaches it, fee-free like the knock-out, and the holder banks |takeProfit - entry| x qty. On a BUY the take profit must sit STRICTLY ABOVE the current mark (and above the entry the maker quotes), the barrier strictly below: read GET /v1/mark-price and place both levels on their correct sides before sending, or the request rejects with 2027. Holder margin is unchanged; the writer's requirement is bounded by the take-profit distance.",
              "value": { "symbol": "BTC-USD-KO", "side": "BUY", "qty": "1", "expiresInMs": 120000, "barrier": { "level": "60000", "takeProfit": "70000" }, "clOrdId": "my-rfq-4", "clientUid": "CLIENT-A" }
            },
            "withRegulatoryFields": {
              "summary": "4. With regulatory fields (needs YOUR venue-issued Trader ID; open-ended like example 1, same maxContractLifeHours condition)",
              "description": "Open-ended like example 1, so it needs a market without maxContractLifeHours or an added barrier.expiryTs inside the cap (2027 otherwise). RFQ creation carries the same regulatory block as order entry and enforces it the same way. REPLACE EVERY IDENTIFIER: once your member has registered Authorised Users a request without a valid traderId rejects with 2021, and until then whatever you send is recorded verbatim on the regulatory record.",
              "value": { "symbol": "BTC-USD-KO", "side": "BUY", "qty": "1", "expiresInMs": 120000, "barrier": { "level": "60000" }, "clOrdId": "my-rfq-3", "clientUid": "CLIENT-A", "reg": { "traderId": "TR-12-9F3A21BC", "tradingCapacity": "MTCH", "clientIdType": "LEI", "clientId": "529900T8BM49AURSDO55", "investmentDecisionId": "ALGO-7", "executionDecisionId": "TRADER-3", "dea": false, "liquidityProvision": false } }
            },
            "barrierStrictTakeProfit": {
              "summary": "4b. STRICT take profit, cheaper, pays only on a touch (needs a take profit AND an expiry within 24 h)",
              "description": "A STRICT take-profit contract (2.24.0): barrier.strictTakeProfit true means the contract pays ONLY if the take profit is touched before barrier.expiryTs; at the expiry without a touch you lose the whole premium whatever the mark. It needs BOTH a take profit and an expiry at most 24 h after the request, on a market whose strictTakeProfitPremiumBps is nonzero (every barrier market listed today: 5000, i.e. the premium is 50 percent of the entry-to-barrier distance x qty instead of the normal 90 percent after the 10 percent knock-out rebate), else 2027. THE expiryTs BELOW MUST BE REPLACED with a timestamp less than 24 hours ahead of the moment you send (the placeholder is deliberately not sendable, so this example never quietly opens a contract; an expiry within 24 h also satisfies any maxContractLifeHours the market publishes), and both levels must sit on their correct sides of the current mark as in example 3.",
              "value": { "symbol": "BTC-USD-KO", "side": "BUY", "qty": "1", "expiresInMs": 120000, "barrier": { "level": "60000", "takeProfit": "70000", "expiryTs": 0, "strictTakeProfit": true }, "clOrdId": "my-rfq-strict-1", "clientUid": "CLIENT-A" }
            },
            "barrierClose": {
              "summary": "5. Close an open barrier contract early (needs a contractId YOU HOLD)",
              "description": "A CLOSE REQUEST (2.23.0): closeContractId names one of YOUR OPEN barrier contracts on this market, taken from GET /v1/barriers (role HOLDER); the 51 below is an illustration of the shape, not a usable id, and an id that is not an open contract you hold on this market rejects with 2035. NO side, qty or barrier: the venue derives the closing side (a long holder SELLs), the full contract quantity and the contract's terms, and sending any of them rejects with 2013. clientUid is omitted here so it defaults to the contract's holder-side client. Only the contract's writer sees and may quote it, at a price strictly inside the barrier and take profit; accepting that quote closes the contract AT the quoted price with terminationReason EARLY_CLOSE, paying maker/taker fees exactly like the entry trade.",
              "value": { "symbol": "BTC-USD-KO", "closeContractId": 51, "expiresInMs": 120000, "clOrdId": "my-rfq-close-1" }
            },
            "swapOffer": {
              "summary": "6. Post a yield contract OFFER (SWAP market; you are the writer and RECEIVE the asset when taken)",
              "description": "A yield contract offer (2.26.0) on BTC-STAKE-SWAP: you offer to take in up to 0.5 BTC for 30 days at 4.5 percent annualised (rateBps 450), any single take at least 0.01 BTC, the offer standing for 24 hours (expiresInMs 86400000). No side, no barrier: the market prices nothing, the terms ARE the offer. When another member takes a size, its principal in BTC moves to your balance at once (a SWAPPRINCIPAL wallet leg) and you owe principal plus the frozen reward (0.5 x 450 x 30 / 3650000 = 0.001849 BTC on the full size) at maturity, paid from your BTC balance by the venue's sweep; maker fee 1 bps of the taken principal at the take. Terms outside the market's admission rule (GET /v1/instruments: swapMinTenorDays..swapMaxTenorDays, swapMaxRateBps, maxOrderQty, minNotional in BTC) reject 2036; if you carry an unpaid claim from an earlier default the venue answers 3008; if you are not a Market Maker Member, or the offer carries a clientUid other than your house uid, 3013 (once GET /v1/instruments swapWriterEligibility reads MARKET_MAKER).",
              "value": { "symbol": "BTC-STAKE-SWAP", "qty": "0.5", "rateBps": 450, "tenorDays": 30, "minQty": "0.01", "expiresInMs": 86400000, "clOrdId": "my-swap-offer-1", "clientUid": "CLIENT-A" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "The created RFQ (requester view).", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Rfq" } } }
          ] } } } },
          "400": { "description": "Rejects include RFQ operation on an order-book market (2023), barrier terms invalid for the market and side (2027), notional below the instrument's minNotional valued at the current mark (2028), unknown field (2017), qty off the qtyStep grid (2002), reserved KX- clOrdId (2020); on a close request: closeContractId not an open contract you hold on this market or a close request already open for it (2035), side / qty / barrier sent alongside closeContractId (2013), a clientUid other than the contract's (2010); on a swap offer (2.26.0): rateBps / tenorDays missing or side / barrier / closeContractId sent (2013), rateBps / tenorDays / minQty on a non-swap market (2013), terms outside the market's admission rule or validity outside 60 s..30 d (2036), writer blocked by an outstanding claim (3008), a member without the Market Maker Member designation, or an offer carrying a clientUid other than your house uid (3013, once GET /v1/instruments swapWriterEligibility reads MARKET_MAKER)." },
          "429": { "description": "Rate limit (1003): creates, quotes and accepts share the order-entry bucket; cancels are always free." }
        }
      }
    },
    "/v1/rfq/open": {
      "get": {
        "tags": ["RFQ"], "operationId": "getRfqOpenBoard", "summary": "The open board: live RFQs you are eligible to quote, and yield contract offers you may take",
        "description": "Requester anonymous, Market Segments respected, your own RFQs excluded (those live under /v1/rfq/mine). Rows carry quoteCount and, where you already have a live quote, myQuote. A CLOSE REQUEST (2.23.0, closeContractId set) is on YOUR board only when you WROTE that contract: nobody else ever sees it, because nobody else may quote it. On a SWAP market (2.26.0, filter with symbol) the board is the OFFERS BOARD: every standing offer of another member you are eligible to trade with, writer anonymous, sorted best for you first (rateBps descending, then rfqId), each with remainingQty, minQty, tenorDays and expiryTs; take a size with POST /v1/rfq/{rfqId}/accept. Polled REST, never pushed: an offer's lifecycle frames reach its writer only.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "symbol", "in": "query", "schema": { "type": "string" }, "example": "BTC-USD-KO" }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Rfq" } } } }
          ] } } } },
          "400": { "description": "Unknown symbol (2001)." }
        }
      }
    },
    "/v1/rfq/mine": {
      "get": {
        "tags": ["RFQ"], "operationId": "getMyRfqs", "summary": "Your own open RFQs, live quotes included (makers anonymous)",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Rfq" } } } }
          ] } } } }
        }
      }
    },
    "/v1/rfq/quotes/mine": {
      "get": {
        "tags": ["RFQ"], "operationId": "getMyRfqQuotes", "summary": "Your live quotes across all open RFQs",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/RfqQuote" } } } }
          ] } } } }
        }
      }
    },
    "/v1/rfq/{rfqId}/quotes": {
      "post": {
        "tags": ["RFQ"], "operationId": "quoteRfq", "summary": "Quote an RFQ",
        "description": "NEEDS A LIVE rfqId FROM SOMEONE ELSE: rfqId is a path parameter with no default, so take one from GET /v1/rfq/open before sending. Quoting your own RFQ rejects with 2026. One live quote per maker per RFQ; a re-quote replaces your previous one, since 2.42.0 (Member API revision 3.85, section 6b) under a NEW clOrdId: a reference you already used answers 2009 and replaces nothing, from the matching engine's replay-contract line for that release. Quotes are negotiated, but the venue still refuses a price outside the instrument's band (2003). On a barrier market you are the WRITER quoting the holder's ENTRY price. On a CLOSE REQUEST (2.23.0, the board row carries closeContractId) you are the writer of that contract quoting the price it CLOSES at: it must lie STRICTLY INSIDE the contract's terms relative to the holder's direction (barrier < price < takeProfit for a long holder, mirrored for a short one; 2027 otherwise), and any member other than the writer is answered 2024.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "rfqId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "A live RFQ you are eligible to quote, from GET /v1/rfq/open. There is no default: the venue mints these ids, so any value written here would be a guess." }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/RfqQuoteRequest" },
          "examples": {
            "barrierEntryQuote": {
              "summary": "1. Quote the entry price on a barrier RFQ",
              "description": "On BTC-USD-KO you are the writer and this is the holder's ENTRY price, on the 0.5 tick grid. It must sit ABOVE the barrier on a BUY request (below it on a SELL) or the quote rejects with 2027, and it must be inside the instrument's price band or it rejects with 2003. Match the price to the request you are answering rather than reusing this number: read the RFQ's barrier and the current mark first.",
              "value": { "price": "66000", "expiresInMs": 30000, "clientUid": "CLIENT-B" }
            },
            "quoteWithReference": {
              "summary": "2. Quote carrying your own reference",
              "description": "Same quote with your own clOrdId attached; it is echoed back on your maker views and never exposed to the requester. Same uniqueness rules as order entry: unique per member per 24 hours, and the KX- prefix is reserved (2020).",
              "value": { "price": "66000", "expiresInMs": 30000, "clOrdId": "my-quote-1", "clientUid": "CLIENT-B" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "Your live quote.", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/RfqQuote" } } }
          ] } } } },
          "400": { "description": "Quoting your own RFQ (2026), entry price incoherent with the barrier (2027; on a close request: a price not strictly inside the contract's terms), price outside band (2003), tick misalignment (2002), RFQ notional below minNotional at your quoted entry price (2028), premiumBps outside [the market's effective share .. 10000] (2044, 2.26.5) or sent on a close request or a non-barrier market (2013)." },
          "404": { "description": "RFQ not found, closed or expired (2024). Also answered when the requester's Market Segments exclude you, and to any member but the contract's writer on a close request." },
          "429": { "description": "Rate limit (1003)." }
        }
      }
    },
    "/v1/rfq/{rfqId}/accept": {
      "post": {
        "tags": ["RFQ"], "operationId": "acceptRfqQuote", "summary": "Accept a quote and trade, or take a yield contract offer",
        "description": "NEEDS ONE OF YOUR OWN RFQs WITH A LIVE QUOTE ON IT: both ids come from GET /v1/rfq/mine, which lists your open RFQs with their live quotes, and neither has a default. THIS TRADES. The requester hits one live quote; the trade prints at the quoted price for the full RFQ quantity, both members margin-checked at accept. On a barrier market this opens the contract and the response carries contractId, after which the position lives under GET /v1/barriers; the accept additionally passes the barrier quote guard (2.26.3, in force on every environment): the accepted entry must lie within the market's barrierGuard.entryBandBps (GET /v1/instruments; 50 unless the market sets its own) of a CURRENT, FRESH mark (2039, also answered while the mark is stale), a takeProfit the mark has already reached is refused (2040), a barrier the mark has already reached or crossed is refused too (2043, the contract would knock out at once), and the takeProfit and the barrier must each sit at least the market's barrierGuard.minTakeProfitBps / minBarrierBps of the entry away from it (10 unless the market sets its own; 2041 / 2042), so REFRESH QUOTES WHEN THE MARK MOVES rather than accepting a stale one. On a CLOSE REQUEST (2.23.0) it CLOSES the contract AT the quoted price instead: a BARRIER_CLOSE trade with maker/taker fees like the entry, a BARRIERSETTLE zero-sum settlement with terminationReason EARLY_CLOSE, no margin admission (closing releases margin), and the response carries contractId (the closed contract), closeContractId, settlePrice and your realizedPnl; 2035 if the contract is no longer open or held, 2027 if the quote no longer lies inside its terms. YIELD CONTRACT TAKE (2.26.0): on a SWAP market the rfqId is ANOTHER member's standing offer from GET /v1/rfq/open and the body names qty (no quoteId): your principal in the market's asset (qty) plus your taker fee (2 bps) move at once (SWAPPRINCIPAL and FEE wallet legs), a trade flagged SWAP prints with price = the rate in bps, and a swap contract opens (contractId; GET /v1/swaps; WS swaps opened) that returns principal plus the frozen reward to you at maturity (openedTs + tenorDays x 24 h) from the writer's balance. Rejects: qty zero or off the qtyStep grid (2002); above the offer's remainder, above your per-order cap or below its minQty without being the remainder (2038); quoteId on a swap offer (2037); insufficient payable balance in the asset (3004); taking your own offer (2026); the writer no longer fit (suspended, reduce-only, in liquidation, defaulted or blocked by a claim: 3007 and the offer is withdrawn) or at its open-swap or contract-count caps (3007 only, the offer stays and a smaller or later take may fit); market halted (3003); an offer you are not eligible to trade with (2024, answered before any other check).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "rfqId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "One of your own open RFQs, from GET /v1/rfq/mine; or, on a SWAP market, another member's offer from GET /v1/rfq/open." }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/RfqAcceptRequest" },
          "examples": {
            "acceptQuote": {
              "summary": "1. Accept a live quote (needs a real quoteId)",
              "description": "quoteId identifies which of the quotes on your RFQ you are hitting; take it from the quotes array of that RFQ under GET /v1/rfq/mine. The 88 below is an illustration of the shape, not a usable id: an unknown, withdrawn or expired quote rejects with 2025.",
              "value": { "quoteId": 88 }
            },
            "acceptWithRegulatoryFields": {
              "summary": "2. Accept with regulatory fields (needs YOUR venue-issued Trader ID)",
              "description": "The accept is an execution decision and carries the same regulatory block, enforced the same way. REPLACE EVERY IDENTIFIER before sending.",
              "value": { "quoteId": 88, "reg": { "traderId": "TR-12-9F3A21BC", "tradingCapacity": "MTCH", "clientIdType": "LEI", "clientId": "529900T8BM49AURSDO55", "investmentDecisionId": "ALGO-7", "executionDecisionId": "TRADER-3", "dea": false, "liquidityProvision": false } }
            },
            "swapTake": {
              "summary": "3. Take a yield contract offer (needs an rfqId from GET /v1/rfq/open on a SWAP market)",
              "description": "A swap TAKE (2.26.0): the rfqId in the path is another member's offer on a SWAP market (GET /v1/rfq/open?symbol=BTC-STAKE-SWAP), and the body names the size you take, no quoteId. THIS MOVES YOUR ASSET: 0.1 BTC leaves your BTC balance now (plus the 2 bps taker fee) and comes back with the reward at the offer's tenor; the response carries the contract (contractId, reward, maturityTs). qty must be at least the offer's minQty (unless it is the whole remainder) and at most its remainingQty, else 2038.",
              "value": { "qty": "0.1", "clOrdId": "my-swap-take-1", "clientUid": "CLIENT-A" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "Trade confirmation.", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/RfqAcceptResult" } } }
          ] } } } },
          "400": { "description": "Token restricted (2049, revision 3.70): on a SECURITY market the instrument, the request's client wallet or the quote's client wallet is frozen on the Kronos X chain, the same gate as the request and the quote, answered before the engine. Insufficient margin on your side (3001), or the quoting member no longer passes margin or limits (3007). Barrier open accept (2.26.3, in force on every environment): entry more than the market's barrierGuard.entryBandBps (GET /v1/instruments; 50 unless the market sets its own) from the current mark, or the mark stale (2039); takeProfit already reached by the mark (2040); barrier already reached or crossed by the mark (2043); takeProfit (2041) or barrier (2042) closer to the entry than the market's barrierGuard.minTakeProfitBps / minBarrierBps (10 unless the market sets its own). Nothing trades and the request and the quote stay open. Close request: the contract is no longer open or held (2035), the quote no longer lies strictly inside its terms (2027). Swap take (2.26.0): qty zero or off-grid (2002), size not admissible (2038), quoteId on an offer (2037), qty / clOrdId / clientUid on a non-swap accept (2013), insufficient asset balance (3004), your own offer (2026), the writer suspended, reduce-only, in liquidation, defaulted or blocked by a claim (3007, the offer is withdrawn) or at its caps (3007 only, the offer stays)." },
          "404": { "description": "RFQ (2024) or quote (2025) not found or expired." },
          "429": { "description": "Rate limit (1003)." }
        }
      }
    },
    "/v1/rfq/{rfqId}/cancel": {
      "post": {
        "tags": ["RFQ"], "operationId": "cancelRfq", "summary": "Cancel your RFQ",
        "description": "Takes an rfqId from GET /v1/rfq/mine; there is no default. Cancels are never rate limited.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "rfqId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
          "description": "One of your own open RFQs, from GET /v1/rfq/mine." }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "rfqId": { "type": "integer", "format": "int64", "example": 1207 },
              "status": { "type": "string", "enum": ["CANCELED"], "example": "CANCELED" }
            } } } }
          ] } } } },
          "404": { "description": "Unknown, expired or not your RFQ (2024)." } }
      }
    },
    "/v1/rfq/{rfqId}/quotes/{quoteId}/cancel": {
      "post": {
        "tags": ["RFQ"], "operationId": "cancelRfqQuote", "summary": "Withdraw your quote",
        "description": "Both ids come from GET /v1/rfq/quotes/mine, which lists your live quotes with the RFQ each one answers; there are no defaults. Cancels are never rate limited.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "rfqId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
            "description": "The RFQ your quote answers, from GET /v1/rfq/quotes/mine." },
          { "name": "quoteId", "in": "path", "required": true, "schema": { "type": "integer", "format": "int64" },
            "description": "Your own live quote, from GET /v1/rfq/quotes/mine." }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "rfqId": { "type": "integer", "format": "int64", "example": 1207 },
              "quoteId": { "type": "integer", "format": "int64", "example": 88 },
              "status": { "type": "string", "enum": ["CANCELED"], "example": "CANCELED" }
            } } } }
          ] } } } },
          "404": { "description": "RFQ not found (2024); quote unknown, withdrawn, expired or not yours (2025)." } }
      }
    },
    "/v1/barriers": {
      "get": {
        "tags": ["RFQ"], "operationId": "getBarrierContracts", "summary": "Your barrier contracts, both roles: live (default) or recently closed",
        "description": "One row per contract you hold or wrote. Default (status omitted or OPEN): the LIVE contracts marked to the live mark; barrierDistance is how far the mark sits from the knock-out, as a decimal fraction of mark. status=CLOSED (revision 3.43): your recently settled contracts, newest first, kept since the last venue start, each with settlePrice, role-signed realizedPnl, terminationReason (KNOCK_OUT | TAKE_PROFIT | EXPIRY | TEAR_UP | FINAL_SETTLEMENT | EARLY_CLOSE) and closedTs in place of the mark-derived figures. status=ALL: both, live rows first. Contracts settle AT the barrier on knock-out, AT the take-profit level on a take profit, at mark on expiry, and AT the writer's accepted quote on an early close (2.23.0: the holder's close request, POST /v1/rfq with closeContractId).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["OPEN", "CLOSED", "ALL"], "default": "OPEN" },
            "description": "OPEN (default, live contracts), CLOSED (recently settled), ALL. Any other value answers 2013." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 },
            "description": "Maximum number of CLOSED rows returned (status CLOSED or ALL); live rows are never limited." }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/BarrierContract" } } } }
          ] } } } }
        }
      }
    },
    "/v1/swaps": {
      "get": {
        "tags": ["RFQ"], "operationId": "getSwapContracts", "summary": "Your yield contracts (SWAP markets), both roles: live (default) or recently closed",
        "description": "One row per swap contract you wrote or took (2.26.0). Default (status omitted or OPEN): the LIVE contracts in the venue registry, status OPEN or DEFAULTED (a claim outstanding after a short settlement at maturity, re-tried every second from the writer's balance). status=CLOSED: your recently closed contracts, newest first, kept since the last venue start, status MATURED (paid in full at maturity) | CURED (a defaulted claim paid to zero) | FINAL_SETTLEMENT (operator close-out of a delisted market at pro rata reward), each with paid and closedTs. status=ALL: both, live rows first. The counterparty is never named; every amount is in the market's asset. Live pushes: the WS swaps channel (types opened, matured, default, cured, finalSettlement) to both parties.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["OPEN", "CLOSED", "ALL"], "default": "OPEN" },
            "description": "OPEN (default, live contracts incl. DEFAULTED), CLOSED (recently closed), ALL. Any other value answers 2013." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 },
            "description": "Maximum number of CLOSED rows returned (status CLOSED or ALL); live rows are never limited." }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/SwapContract" } } } }
          ] } } } }
        }
      }
    },
    "/v1/stream/events": {
      "get": {
        "tags": ["Event stream recovery"], "operationId": "getStreamEvents", "summary": "Seq-cursored backfill of missed WebSocket event-class messages",
        "description": "Ascending replay, in engine order, of every event-class message the private socket delivers (order, execution, wallet, margin calls, adl executions, unwind, eligibility, funding settlements, venue status, swaps). Each event carries a 30-character fixed-width numeric cursor (seq, eventIndex, leg); ordinal string comparison equals engine order. A backfilled data object is byte-identical to the live frame's data. Pass EXACTLY ONE of afterCursor (exclusive) or fromSeq (inclusive). The envelope asOfSeq and store.contiguousThroughSeq are the projection watermark, never the engine head; store.status is COMPLETE, CATCHING_UP or REPAIRING. Requires the event store; deployments without it answer 5004 with HTTP 503.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "afterCursor", "in": "query", "schema": { "type": "string", "minLength": 30, "maxLength": 30, "pattern": "^[0-9]{30}$" }, "example": "000000000000010487100000000040",
            "description": "Exclusive lower bound: the nextCursor of your previous page, or the cursor of the last event you processed. REPLACE THE PREFILLED VALUE with a cursor you stored (or one from GET /v1/stream/cursor); the value shown illustrates the 30-character fixed-width shape and is not a position in your own stream, so as it stands it simply returns whatever happens to follow it. Pass exactly one of afterCursor or fromSeq. Since 2.40.0 the field ranges are stated (Member API revision 3.83, section 11.2): characters 1 to 19 are seq, 0 to 9223372036854775807; characters 20 to 29 are eventIndex, 0 to 2147483647; character 30 is the leg. A field above its range answers 2019 with a msg naming the field and its range; anything that is not 30 ASCII digits answers 2019 afterCursor must be 30 numeric characters." },
          { "name": "fromSeq", "in": "query", "schema": { "type": "integer", "format": "int64", "minimum": 1 } },
          { "name": "toSeq", "in": "query", "schema": { "type": "integer", "format": "int64", "minimum": 1 } },
          { "name": "channels", "in": "query", "schema": { "type": "string" }, "example": "order,execution,wallet",
            "description": "CSV of: order, execution, wallet, margin, adl, unwind, eligibility, funding, status, swaps (2.26.0). Default all ten. Since 2.37.0 (Member API revision 3.73) a value that names no family (an empty value, commas only) answers 5003." },
          { "name": "symbol", "in": "query", "schema": { "type": "string" },
            "description": "Excludes rows that are not instrument-scoped (wallet, margin, eligibility, unwind, venue halt/resume)." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 2000, "default": 500 } },
          { "name": "waitMs", "in": "query", "schema": { "type": "integer", "minimum": 0, "maximum": 2000, "default": 0 },
            "description": "Bounded wait for the store to reach the requested upper bound; the answer is authoritative with or without it." }
        ],
        "responses": {
          "200": { "description": "Page of events plus fromCursor, nextCursor, hasMore, count and the store staleness block { contiguousThroughSeq, engineSeq, lagSeq, status, complete }.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "fromCursor": { "type": "string", "minLength": 30, "maxLength": 30, "description": "The effective exclusive lower bound of this page." },
                "nextCursor": { "type": "string", "minLength": 30, "maxLength": 30, "description": "Pass as afterCursor on your next call. On a page with hasMore true the cursor of the last event. On a page with hasMore false, since 2.37.0 (Member API revision 3.73), a position at the store watermark of this page or at toSeq when lower (eventIndex 2147483647, leg 9, like a fromSeq fromCursor), never below fromCursor, valid only with the same channels and symbol. Stop paging on hasMore false or count 0, never on nextCursor equal to afterCursor. Since 2.40.0 the condition is stated (Member API revision 3.83, section 11.3): the venue serves this last-page position on an environment from the date venue operations announce for it there; before that date, and on a page read while the store recorded or cleared a hole, a last page answers the cursor of its last event, else fromCursor." },
                "hasMore": { "type": "boolean", "example": false },
                "count": { "type": "integer", "example": 2 },
                "events": { "type": "array", "items": { "$ref": "#/components/schemas/StreamEvent" }, "description": "Ascending engine order." },
                "store": { "$ref": "#/components/schemas/StreamStore" }
              } } } }
            ] } } } },
          "400": { "description": "Parameter error (5003; since 2.37.0 also a channels value that names no family), malformed cursor or unknown channel (2019), unknown symbol (2001)." },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Event store not configured (5004, permanent), or, since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); branch on the code." }
        }
      }
    },
    "/v1/stream/cursor": {
      "get": {
        "tags": ["Event stream recovery"], "operationId": "getStreamCursor", "summary": "Your stream head cursor and the retention boundary",
        "description": "headCursor is the newest stream row visible to you at the projection watermark (omitted when you have none); retentionFromCursor is the oldest row still retained. If your stored cursor is older than the retention boundary, full backfill is impossible: fall back to snapshot reads plus the dated history routes. Mirrored over WS as get.streamCursor.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "headCursor": { "type": "string", "nullable": true, "minLength": 30, "maxLength": 30, "description": "Omitted when you have no stream rows yet." },
              "headSeq": { "type": "integer", "format": "int64", "example": 918273, "description": "0 when you have no stream rows yet." },
              "retentionFromCursor": { "type": "string", "nullable": true, "minLength": 30, "maxLength": 30, "description": "Oldest row still retained; omitted when the store is empty." },
              "retentionFromSeq": { "type": "integer", "format": "int64", "example": 1 },
              "store": { "$ref": "#/components/schemas/StreamStore" }
            } } } }
          ] } } } },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Event store not configured (5004, permanent), or, since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); branch on the code." } }
      }
    },
    "/v1/margin/calls": {
      "get": {
        "tags": ["Event stream recovery"], "operationId": "getMarginCalls", "summary": "Margin-call notice history",
        "description": "Descending history of MARGIN_CALL notices with equity, im, mm, available and ccy at the time of the call, each with its stream cursor. Served from the event store and clamped to the projection watermark.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, inclusive." },
          { "name": "to", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, inclusive." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 } }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/MarginCall" }, "description": "Newest first." } } }
          ] } } } },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Event store not configured (5004, permanent), or, since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); branch on the code." } }
      }
    },
    "/v1/account": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getAccount", "summary": "Balance, equity, margin, spot reservations and asset holdings",
        "description": "One row per settlement currency. Each row carries imMultiplier (exact decimal string, '1' unless the venue runs this member at a stricter margin profile): effective initial margin = instrument tier rate times this value, and the order-level leverage assertion validates against that member-effective figure.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Account" }, "description": "One row per settlement currency." } } }
        ] } } } } }
      }
    },
    "/v1/account/parameters": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getAccountParameters", "summary": "Every parameter the venue applies to your account, with the scope that supplies each value",
        "description": "2.27.0 (section 7, Your effective parameters). The market rules are public on GET /v1/instruments; this read answers what applies to YOU: per parameter the effective value and its source scope (VENUE, MARKET, MEMBER, MEMBER_MARKET, and since 2.30.0 SELF and SELF_MARKET for the values you set yourself on the PUT below, listed raw under self), at account level and for every listed market, plus your rate-limit and order-to-trade classes, your fee resolution, your margin-watch level and the historical per-account quantity override. A member-specific value only ever TIGHTENS a market rule; a stored value a tighter scope beats is listed under inert on the same row so what the venue stores for you and what is in force are both visible. Only your own values are ever returned. A READ_ONLY credential may call it. Changes to your own values arrive on the WebSocket venueEvents channel as MEMBER_PARAMS frames (section 10.9); re-read this route on each.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AccountParameters" } } }
        ] } } } } }
      },
      "put": {
        "tags": ["Account and positions"], "operationId": "setAccountParameters", "summary": "Set or clear your own tighter limits (account-wide or for one market)",
        "description": "2.30.0 (section 7, Your own tighter limits). Your own pre-trade limits within the venue's rules (RTS 7 Art 20, RTS 6 Art 15): a smaller open-order, order-size, position, open-RFQ or open-contract cap, a tighter band or collar, a larger initial margin multiplier, account-wide (no symbol) or on one market (symbol). The venue resolves the TIGHTEST of the market rule, any value venue operations set for your account and your own value, so a self-set value can only tighten what is in force: a looser one is refused with 5003 and a sentence naming the rule it would loosen, before anything is written; so is a quantity cap (maxOrderQty, maxPositionQty) on a market that carries the matching notional cap, where only the notional arm is read (the sentence names the notional name to set instead). Values you set are yours to clear again (clear); venue operations never edit them. TRADE credential. The answer carries what was written and the effective values afterwards; the read shows a value of yours in force as source SELF or SELF_MARKET and lists every value you hold under self. Your other WebSocket sessions receive a MEMBER_PARAMS frame with origin MEMBER (section 10.9).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountParametersWrite" },
          "examples": {
            "marketCaps": { "summary": "1. Tighter order and position caps on one market", "description": "Notionals (and, on a market without a notional cap, quantities) are decimal strings on the market's grid; both must be at or below the market caps and any value venue operations set for you there. BTC-USD-PERP carries notional caps, so the notional names are the ones that bind there.", "value": { "symbol": "BTC-USD-PERP", "set": { "maxOrderNotional": "250000", "maxPositionNotional": "500000" } } },
            "accountBand": { "summary": "2. A tighter price band and a larger margin multiplier, account-wide", "description": "bps as integers, the multiplier as a decimal string at least 1.", "value": { "set": { "priceBandBps": 300, "imMultiplier": "1.5" } } },
            "clear": { "summary": "3. Remove a value of yours so the venue's rule applies again", "value": { "symbol": "BTC-USD-PERP", "clear": ["maxOrderNotional"] } }
          } } } },
        "responses": {
          "200": { "description": "OK. data is { scope, symbol, set, cleared, parameters } with the effective values afterwards.", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AccountParametersWriteResult" } } }
          ] } } } },
          "400": { "description": "5003 with the refusal sentence (a value that would loosen the rule in force or the venue's value for you, a range error, a parameter that is not self-service, a per-market value without symbol); 2001 unknown symbol; 1005 READ_ONLY credential.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } }
        }
      }
    },
    "/v1/account/stp": {
      "put": {
        "tags": ["Account and positions"], "operationId": "setAccountStp", "summary": "Elect your self-trade prevention policy and scope",
        "description": "2.28.0 (section 6, Self-trade prevention; section 7). Your own choice within the venue's rules: stp is what happens when two of your orders with the same clientUid (or house account) would match (CANCEL_RESTING, CANCEL_TAKER, CANCEL_BOTH, REJECT_TAKER), stpScope END_CLIENT (per clientUid, the default) or MEMBER (no same-member matching at all). Name one or both fields; an omitted field keeps its value. TRADE credential. The result is the pair now in force, also on GET /v1/account and GET /v1/account/parameters. Orders of the same end client never match under any policy.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccountStpRequest" },
          "examples": {
            "strictMemberWide": { "summary": "1. Reject the taker and prevent any same-member match", "description": "REJECT_TAKER refuses the incoming order instead of cancelling anything; MEMBER widens prevention from the same clientUid to every order of your account.", "value": { "stp": "REJECT_TAKER", "stpScope": "MEMBER" } },
            "policyOnly": { "summary": "2. Change the policy, keep the scope", "description": "An omitted field keeps its current value.", "value": { "stp": "CANCEL_BOTH" } }
          } } } },
        "responses": { "200": { "description": "OK. data is { stp, stpScope } as now in force.", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/AccountStpRequest" } } }
        ] } } } } }
      }
    },
    "/v1/account/margin": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getAccountMargin", "summary": "Same payload as /v1/account (cheap polling alias)",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Account" }, "description": "One row per settlement currency." } } }
        ] } } } } }
      }
    },
    "/v1/margin/preview": {
      "post": {
        "tags": ["Account and positions"], "operationId": "previewMargin", "summary": "What-if margin and prefunding check for a basket of hypothetical orders",
        "description": "A READ: nothing is placed and no order-budget unit is consumed. The orders array is priced as ONE BASKET of 1 to 50 entries (more reject with 2002): the figures answer \"what would my margin state be if ALL of these were working at once, on top of what I already hold\". Perpetual entries fold into order margin together, with the same one-sided max(buy, sell) netting per instrument that resting orders receive, so two buys add while a buy and a sell on one instrument cost the larger side; spot entries have their prefunding needs summed per currency, and accepted answers every gate at once. The result is independent of array order. Each entry takes the same shape as POST /v1/orders and is validated the same way, with one deliberate exception: reg.traderId is not enforced here, because a preview is a risk-tooling read rather than order entry. Every OTHER check still applies, so an entry carrying a leverage assertion the instrument cannot satisfy fails the preview with 2018 exactly as it would fail the order. im, mm and available describe the WHOLE basket, in the settlement currency of the first entry (every current listing settles in USD).\n\nHow entries are PRICED. A priced entry is valued at its own limit, a conditional at the limit it would work at once armed (limitPrice), and a MARKET entry at the current mark, on perpetual and spot markets alike. The mark is what the venue already values a market order at for the per-order size cap and the minNotional floor. It is NOT the price a market order would actually get: the protection collar forms from the book at the instant of entry, so a market entry's answer is an indication at today's mark, not a quote. Size a market order against the book, or send a limit. On a SPOT market buy that difference is a funding one: order entry prefunds the order at the collar, which is normally above the mark, so a spot market buy sized to the last micro of your cash can preview accepted and still be rejected 3001 when you send it.\n\nWhat accepted answers. Entry by entry, the same admission rules placement applies: available (perpetual order margin, spot buy prefunding in cash and spot sell prefunding in base-asset units, summed per currency), the per-order size cap (2013), the minNotional floor (2028), the position cap (2011) and the reduce-only budget (2008). The reduce-only asymmetries are mirrored too: a reduceOnly entry is EXEMPT from the available gate, from minNotional and from the position cap, exactly as it is when you send it, so a reduce-only basket previewed during a margin call answers accepted rather than rejected; it is NOT exempt from the per-order size cap, because that cap guards closes as well; and it is held to the reduce-only budget instead of the position cap, so a basket that would close MORE than you hold on that market answers rejected, measured over the whole basket against your open position less the reduce-only quantity already working. What accepted does not answer is venue state that is not a property of your basket: halts, member or instrument status, and whether a market order would find liquidity.\n\nRejections that are not admission gates. An entry the venue would refuse outright answers with the code order entry answers, as a 400 rather than through accepted: a reduceOnly entry or a market-type conditional BUY on a spot market gives 2016, an out of range trigger price or post-trigger limit price gives 2013, a market with no sequenced mark yet gives 3005, a limit priced at zero gives 2002, and an entry whose leverage or quoteCcy assertion the instrument cannot satisfy gives 2018. The basket answers with the first such entry.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/MarginPreviewRequest" },
          "examples": {
            "singleOrder": {
              "summary": "1. Margin for one hypothetical order (executes today)",
              "description": "Answers with indicative, accepted, im, mm and available for this order as if it were placed now, on top of whatever you already hold.",
              "value": { "orders": [
                { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.01", "clOrdId": "my-preview-1", "clientUid": "CLIENT-A" }
              ] }
            },
            "conditionalOrder": {
              "summary": "2. Margin for a conditional order (executes today)",
              "description": "A conditional is priced at the limit it would work at once armed, which is limitPrice, exactly as the per-order cap and the minNotional floor measure it.",
              "value": { "orders": [
                { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "STOP_LIMIT", "tif": "GTC", "qty": "0.01", "clOrdId": "my-preview-2", "clientUid": "CLIENT-A", "trigger": { "source": "MARK", "price": "72000", "direction": "AT_OR_ABOVE", "limitPrice": "72200" } }
              ] }
            },
            "twoOrderBasket": {
              "summary": "3. Margin for a two-order basket (executes today)",
              "description": "Both entries are priced together: im, mm and available answer for the account with BOTH orders working at once, and accepted means the whole basket clears. Here the instruments differ, so the two margin contributions simply add; two same-side entries on ONE instrument add too, while a buy and a sell on one instrument cost only the larger side, exactly as they would once resting.",
              "value": { "orders": [
                { "symbol": "BTC-USD-PERP", "side": "BUY", "type": "LIMIT", "tif": "GTC", "price": "69000", "qty": "0.01", "clOrdId": "my-preview-3a", "clientUid": "CLIENT-A" },
                { "symbol": "ETH-USD-PERP", "side": "SELL", "type": "LIMIT", "tif": "GTC", "price": "3450", "qty": "0.05", "clOrdId": "my-preview-3b", "clientUid": "CLIENT-B" }
              ] }
            }
          }
        } } },
        "responses": { "200": { "description": "OK. data carries indicative, accepted, im, mm and available.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/MarginPreview" } } }
            ] } } } },
          "400": { "description": "An entry failed the same validation an order would, and answers with the same code: grid misalignment or a zero limit price (2002), an out of range trigger or post-trigger limit price (2013), reduceOnly or a market-type conditional buy on a spot market (2016), unknown field (2017), assertion mismatch (2018), no sequenced mark on the market yet (3005), funding catch-up pending on the market (3014)." } }
      }
    },
    "/v1/positions": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getPositions", "summary": "Member-level positions",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "symbol", "in": "query", "schema": { "type": "string" } }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Position" }, "description": "Open positions only; flat markets are omitted." } } }
        ] } } } } }
      }
    },
    "/v1/positions/end-clients": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getEndClientPositions", "summary": "Per-clientUid sub-positions",
        "description": "Informational ledger for your own client reconciliation. Margin is enforced at member level only.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" } },
          { "name": "clientUid", "in": "query", "schema": { "type": "string" }, "example": "CLIENT-A" }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Position" }, "description": "Every row carries its clientUid." } } }
        ] } } } } }
      }
    },
    "/v1/reconciliation/end-client-positions": {
      "get": {
        "tags": ["Account and positions"], "operationId": "getEndClientPositionsEod", "summary": "The end-of-day snapshot of your end clients' sub-positions for one day, JSON or CSV",
        "description": "2.39.0: documented for the first time (served since the venue's first release). The venue's end-of-day snapshot of YOUR end clients' sub-positions for one business day, the record to reconcile your own per-client ledger against: one row per non-flat (clientUid, symbol, positionSide), as the venue's history store held it when the venue's daily anchor ran, within about five minutes after 00:00 UTC for the day that just ended (so a fill of the first minutes of the new day can be in it). If the venue restarts, or another of its nodes takes over, before the next anchor, the anchor runs again for the previous day and adds the rows of the sub-positions that day does not hold yet, from the state at that moment, mark and upnl included (all of the day's rows when the anchor had not run at midnight); a snapshot venue operations take by hand does the same. Rows are immutable once written; a day without a snapshot answers an empty list. upnl (since 2.39.0, Member API 3.81) is the exact unrealized PnL GET /v1/positions/end-clients reports at the snapshot's mark, written only where the history store's net quantity for the row equalled the matching engine's at that instant, else omitted. format=csv answers text/csv WITHOUT the envelope: the header date,clientUid,symbol,positionSide,netQty,avgEntry,mark,upnl, then one line per row with date as YYYY-MM-DD (corrected in 2.39.0: before, the CSV printed it month first, MM/DD/YYYY), positionSide NET on netting rows, an absent value as an empty field, and a field holding a comma, a double quote, CR or LF quoted per RFC 4180 with inner quotes doubled; nothing else is escaped, so a spreadsheet may evaluate a clientUid that begins with = or @. Any other format value answers JSON. Served from the venue's history store: the envelope asOfSeq is the store watermark.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "date", "in": "query", "required": true, "description": "The business day, YYYY-MM-DD; a value that is no date answers 5003.", "schema": { "type": "string", "format": "date" }, "example": "2026-10-18" },
          { "name": "format", "in": "query", "description": "csv for text/csv without the envelope; json, or any other value, for the envelope.", "schema": { "type": "string", "enum": ["json", "csv"], "default": "json" } }
        ],
        "responses": { "200": { "description": "OK", "content": {
          "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/EodClientPosition" } } } }
          ] } },
          "text/csv": { "schema": { "type": "string" },
            "example": "date,clientUid,symbol,positionSide,netQty,avgEntry,mark,upnl\n2026-10-18,CLIENT-A,BTC-USD-PERP,NET,0.002,68000.5,69000,1.999\n2026-10-18,\"CL,B\",BTC-USD-PERP,LONG,0.001,68000,,\n" } } },
          "400": { "description": "date is not a date (5003)." },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); nothing changed on your account." } }
      }
    },
    "/v1/clients/{clientUid}/identity": {
      "put": {
        "tags": ["Client identity"], "operationId": "putClientIdentity", "summary": "Submit or update RTS 22 identification for one clientUid",
        "description": "Upsert of the identity record behind a clientUid, for the transaction reports the venue owes under MiFIR Article 26(5) for members that are not MiFID II investment firms (MiFID II firms report their own transactions and never need this surface). DECOUPLED from order entry: trading is never blocked on identity data; the report is due by close of the following working day, and GET /v1/clients/identity/missing is the chase list inside that window. The body is STRICT like order entry (unknown field 2017); validation failures reject with 2030 and a msg naming the offending field. Every PUT replaces the current record AND appends an immutable audit revision; the response echoes the stored record with its new monotonic revision and the resolved mifirId/mifirIdSource. Requires a trading-capable credential: a READ_ONLY (drop copy) key answers 1005. A market maker can register its own LEI against its house clientUid so own-account sides resolve too. Metered on the read bucket (reference data, not order entry); the identity store sits outside the engine sequence, so the envelope asOfSeq is 0 here.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "clientUid", "in": "path", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 64 }, "example": "CLIENT-A",
            "description": "The end-client identifier exactly as you stamp it on orders." }
        ],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/ClientIdentityRequest" },
          "examples": {
            "naturalPersonWithNationalId": {
              "summary": "1. Natural person with a designated national identifier (executes today)",
              "description": "The stored mifirId is the national identifier (mifirIdSource NATIONAL_ID, mifirIdScheme NIDN). PESEL is the first-priority Annex II identifier for PL, so identifierPriority resolves to 1 (sending 1 is fine, sending another rank contradicts the table). A DE natural person, by contrast, is identified by CONCAT only: a passport for DE is a table contradiction, stored and reported in warnings during the WARN rollout stage.",
              "value": { "type": "NATURAL_PERSON", "countryCode": "PL", "nationalIdType": "PESEL", "nationalId": "44051401359", "firstName": "Jan", "surname": "Kowalski", "dateOfBirth": "19440514" }
            },
            "naturalPersonConcat": {
              "summary": "2. Natural person without a national identifier: the venue derives CONCAT (executes today)",
              "description": "With no nationalId the venue derives the RTS 22 CONCAT code: countryCode + dateOfBirth + first five letters of the first first name + first five of the surname, titles and listed surname prefixes removed, uppercased, folded per the exact ESMA transliteration table (characters outside the table removed), #-padded (ESMA transaction reporting guidelines, section 5.5.1). This body stores mifirId DE19840217JURGEMULLE with mifirIdSource CONCAT.",
              "value": { "type": "NATURAL_PERSON", "countryCode": "DE", "firstName": "Jürgen", "surname": "Müller", "dateOfBirth": "19840217" }
            },
            "legalEntity": {
              "summary": "3. Legal entity: LEI, checksum validated (executes today)",
              "description": "lei is required for LEGAL_ENTITY and is validated against the ISO 17442 MOD 97-10 checksum; a natural-person field on a legal entity rejects with 2030. The stored mifirId is the LEI.",
              "value": { "type": "LEGAL_ENTITY", "countryCode": "DE", "lei": "529900T8BM49AURSDO55" }
            },
            "houseUidOwnLei": {
              "summary": "4. Market maker registering its own LEI against its house UID (send YOUR house identifier in the path)",
              "description": "A market maker whose omitted clientUid resolves to the configured house identifier registers its OWN LEI against that identifier, so own-account trade sides resolve in the venue's reports too. Put the house identifier in the path; the body is an ordinary legal-entity record.",
              "value": { "type": "LEGAL_ENTITY", "countryCode": "CY", "lei": "213800WAVVOPS85N2205" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "The stored record, with the resolved mifirId/mifirIdSource and the new revision. The envelope asOfSeq is 0: the identity store sits outside the engine sequence.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/ClientIdentity" } } }
            ] } } } },
          "400": { "description": "Validation failure (2030, the msg names the offending field: type, required fields per client type, ISO 3166-1 alpha-2 countryCode, YYYYMMDD dateOfBirth, identifierPriority outside 1 to 3, nationalId/nationalIdType not set together, an LEI failing the ISO 17442 format or checksum, or, in the ENFORCE stage of the Annex II rollout (production from its first day, sandbox from Tuesday 2026-09-22), a label, rank, format or CONCAT choice the RTS 22 Annex II table contradicts), an unknown JSON field (2017), or, since 2.36.0, a clientUid in the path that begins or ends with whitespace (2013; percent-encoded whitespace counts)." },
          "403": { "description": "READ_ONLY credential (1005): identity submission needs a trading-capable key." },
          "503": { "description": "Client identity store not configured on this deployment (5004): it requires the venue's history store." }
        }
      },
      "get": {
        "tags": ["Client identity"], "operationId": "getClientIdentity", "summary": "The current identity record for one clientUid",
        "description": "The record as stored, in exactly the PUT echo shape, including mifirId, mifirIdSource and the current revision. A READ_ONLY credential may call it, so a back-office reporting process can verify coverage without being able to trade. The envelope asOfSeq is 0 here (the identity store sits outside the engine sequence).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "clientUid", "in": "path", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 64 }, "example": "CLIENT-A" }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/ClientIdentity" } } }
          ] } } } },
          "400": { "description": "Since 2.36.0: a clientUid in the path that begins or ends with whitespace (2013)." },
          "404": { "description": "No identity record on file for this clientUid (2031); also after the venue pseudonymised the record at the retention floor (section 6d)." },
          "503": { "description": "Client identity store not configured on this deployment (5004)." }
        }
      }
    },
    "/v1/trader-ids/{traderId}/identity": {
      "put": {
        "tags": ["Client identity"], "operationId": "putTraderIdentity", "summary": "Submit or update the identity behind one of your Trader IDs (RTS 22 fields 57 to 60)",
        "description": "Since revision 3.53. For the legs the venue reports under MiFIR Article 26(5), fields 57 to 60 (investment decision within firm, execution within firm, and their branch countries) must carry the natural person under the RTS 22 Annex II identifier scheme (or the algorithm code), never a house code. This route resolves a Trader ID you stamp on orders (reg.traderId, and the codes you send as reg.executionDecisionId and reg.investmentDecisionId) to a PERSON (countryCode, names, dateOfBirth, optional nationalIdType/nationalId under the Annex II table exactly as on the client identity route, plus the mandatory branchCountry) or an ALGO (algoId). The traderId in the path is 1 to 64 characters of A-Z a-z 0-9 . _ - and need not be a registered Authorised User (decision codes may name persons who never enter orders). STRICT body (2017), validation 2030, trading-capable key (1005), immutable audit revisions like the client identity store; the identity store sits outside the engine sequence (asOfSeq 0). MiFID II firm members report their own fields 57 to 60 and need not use this route.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "traderId", "in": "path", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 64 }, "example": "TR-7-A1B2C3D4" }
        ],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/TraderIdentityRequest" },
          "examples": {
            "person": {
              "summary": "1. A natural person trader with a designated national identifier and the branch country",
              "value": { "kind": "PERSON", "countryCode": "PL", "nationalIdType": "PESEL", "nationalId": "44051401359", "firstName": "Jan", "surname": "Kowalski", "dateOfBirth": "19440514", "branchCountry": "CY" }
            },
            "algo": {
              "summary": "2. An algorithm: the code you report it under",
              "value": { "kind": "ALGO", "algoId": "MM-ENGINE-7" }
            }
          }
        } } },
        "responses": {
          "200": { "description": "The stored identity with the resolved mifirId and mifirIdScheme, the new revision and, on this echo only, any Annex II warnings.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/TraderIdentity" } } }
            ] } } } },
          "400": { "description": "Validation failure (2030: kind, the PERSON rules of the client identity route, branchCountry, or the ALGO code shape), an unknown JSON field (2017), or, since 2.36.0, a traderId in the path that begins or ends with whitespace (2013; before 2.36.0 the alphabet rule answered 2030 for it)." },
          "403": { "description": "READ_ONLY credential (1005)." },
          "503": { "description": "Trader identity store not configured on this deployment (5004): it requires the venue's history store." }
        }
      },
      "get": {
        "tags": ["Client identity"], "operationId": "getTraderIdentity", "summary": "The current identity behind one of your Trader IDs",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "traderId", "in": "path", "required": true, "schema": { "type": "string", "minLength": 1, "maxLength": 64 }, "example": "TR-7-A1B2C3D4" }
        ],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/TraderIdentity" } } }
          ] } } } },
          "400": { "description": "Since 2.36.0: a traderId in the path that begins or ends with whitespace (2013)." },
          "404": { "description": "No identity on file for this Trader ID (2031); also after the venue pseudonymised the record at the retention floor (section 6d)." },
          "503": { "description": "Trader identity store not configured on this deployment (5004)." }
        }
      }
    },
    "/v1/clients/identity/missing": {
      "get": {
        "tags": ["Client identity"], "operationId": "getMissingClientIdentities", "summary": "Your clientUids that traded on MiFIR-scope markets with no identity record",
        "description": "The chase list for the reporting window: every distinct clientUid of your member that traded on MiFIR-scope markets (the perpetual AND the barrier markets, both transaction-reportable derivatives; revision 3.52) inside the window and has no identity record on file, oldest first trade first, with the trade sides and first/last trade timestamps that bound the exposure. Spot activity does not appear. The envelope asOfSeq is the PROJECTION WATERMARK, not the engine head: a trade acked a moment ago may not be visible in this report yet. An empty clients array means every reportable side in the window is covered.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "from", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, inclusive. Default: to minus 48 hours. Pass it yourself to sweep further back, for example on the working day after a weekend." },
          { "name": "to", "in": "query", "schema": { "type": "integer", "format": "int64" }, "description": "Unix ms, exclusive. Default: now." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 500 } }
        ],
        "responses": {
          "200": { "description": "OK. data is { from, to, clients: [ { clientUid, tradeSides, firstTradeTs, lastTradeTs } ] }.",
            "content": { "application/json": { "schema": { "allOf": [
              { "$ref": "#/components/schemas/Envelope" },
              { "type": "object", "properties": { "data": { "type": "object", "properties": {
                "from": { "type": "integer", "format": "int64", "example": 1784913600000, "description": "The effective inclusive lower bound of the window." },
                "to": { "type": "integer", "format": "int64", "example": 1785000000000, "description": "The effective exclusive upper bound of the window." },
                "clients": { "type": "array", "description": "Oldest first trade first, so the entries closest to the reporting deadline come first.", "items": { "type": "object", "properties": {
                  "clientUid": { "type": "string", "example": "CLIENT-B" },
                  "tradeSides": { "type": "integer", "format": "int64", "example": 7, "description": "Your trade sides carrying this identifier inside the window." },
                  "firstTradeTs": { "type": "integer", "format": "int64", "example": 1784920000123 },
                  "lastTradeTs": { "type": "integer", "format": "int64", "example": 1784999911456 }
                } } }
              } } } }
            ] } } } },
          "503": { "description": "Client identity store not configured on this deployment (5004)." }
        }
      }
    },
    "/v1/chain/wallets": {
      "get": {
        "tags": ["DLT Market"], "operationId": "getChainWallets", "summary": "Your wallets on the Kronos X chain",
        "description": "2.32.0 (Member API 3.66, section 6i). One custody wallet per clientUid you traded or registered, your house wallet, and the external wallets you sponsor, with holdings per ISIN (free, locked = in trading). READ_ONLY may call it. 2.35.0 (revision 3.70): a custody wallet id is the venue's keyed derivation, read here, never computed; rows carry house and, on an external wallet, clientRef (the custody wallet id of the client it trades for).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "{ height, wallets: [ { id, class, clientUid, house, status, professional, hasOwnKey, publicKey, clientRef, balances: [ { isin, free, locked, unitScale } ] } ] }; NOT the standard envelope (2.35.0: typed as served).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainWalletsResult" } } } } }
      }
    },
    "/v1/chain/wallets/custody": {
      "post": {
        "tags": ["DLT Market"], "operationId": "registerCustodyWallet", "summary": "Register a client's custody wallet",
        "description": "2.32.0. { clientUid, professional }. The venue also creates the wallet at the client's first fill. Since 2.35.0 (Member API 3.70) the body and the answer are typed in this document as served, the answer carries walletId (the venue's keyed derivation for that client, never computable by you: the clientRef of an external wallet registration and the id GET /v1/chain/wallets lists), and the route is metered on your order bucket like every chain write.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainCustodyWalletRequest" },
          "examples": {
            "retailClient": { "summary": "1. A custody wallet for a retail client", "description": "The wallet id is derived by the venue from your credential and the clientUid; the answer's chain.txHash is Final after the next block.", "value": { "clientUid": "INV-1", "professional": false } },
            "professionalClient": { "summary": "2. A professional client's wallet", "value": { "clientUid": "INV-2", "professional": true } }
          } } } },
        "responses": { "200": { "description": "{ chain: { txHash, kind, state, height, reason }, walletId }, NOT the standard envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainCustodyWalletResult" } } } }, "400": { "description": "2013 (an unreadable body, a clientUid over 64 characters); 5003 with chain (state Rejected, reason)" }, "403": { "description": "READ_ONLY credential (1005)." }, "429": { "description": "1003: the order bucket is exhausted, retryAfterMs." } }
      }
    },
    "/v1/chain/transfers": {
      "post": {
        "tags": ["DLT Market"], "operationId": "custodyTransfer", "summary": "Move units out of one of your custody wallets",
        "description": "2.32.0. { clientUid, isin, to, units }. Your engine balance is debited first (a debit above your free balance in the ISIN: 3001 INSUFFICIENT_MARGIN in the standard envelope, nothing moves); a chain refusal re-credits you and answers 5003 with chain.reason. Since 2.35.0 (Member API 3.70) EVERY refusal of the operation is 5003 with chain (state Rejected, reason): unknown isin, no custody wallet for that clientUid, destination wallet unknown, units must be positive, each before any debit; the source wallet is derived from your credential and the clientUid. 3012 while the validator quorum is not reached.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainTransferRequest" },
          "examples": {
            "moveOut": { "summary": "1. Move 100 units of a client's holding to another wallet", "description": "Your engine balance in the ISIN is debited first; the units move at finality, and a chain refusal after the debit re-credits you.", "value": { "clientUid": "INV-1", "isin": "XS0000000777", "to": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "units": 100 } }
          } } } },
        "responses": { "200": { "description": "{ chain: { txHash, kind, state, height, reason } }, NOT the standard envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainInstructionResult" } } } }, "400": { "description": "2013 (an unreadable body, a malformed wallet id, units above the per-instruction cap); 3001 (envelope), 3012, 5003 with chain.reason, 5006" }, "403": { "description": "READ_ONLY credential (1005)." }, "429": { "description": "1003: the order bucket is exhausted, retryAfterMs." } }
      }
    },
    "/v1/chain/unlock": {
      "post": {
        "tags": ["DLT Market"], "operationId": "chainUnlock", "summary": "Return units of a sponsored external wallet from trading to free",
        "description": "2.32.0. { wallet, isin, units }. Engine debited first (3001 above your free balance, nothing moves); a wallet you do not sponsor, an unknown isin or non-positive units: 5003 with chain.reason, state Rejected (2.35.0, Member API 3.70).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainUnlockRequest" },
          "examples": {
            "unlock": { "summary": "1. Return 50 units of a sponsored external wallet to free", "description": "The wallet must be an External wallet you sponsor; your engine balance is debited first.", "value": { "wallet": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "isin": "XS0000000777", "units": 50 } }
          } } } },
        "responses": { "200": { "description": "{ chain: { txHash, kind, state, height, reason } }, NOT the standard envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainInstructionResult" } } } }, "400": { "description": "2013 (an unreadable body, a malformed wallet id, units above the per-instruction cap); 3001 (envelope), 3012, 5003 with chain.reason, 5006" }, "403": { "description": "READ_ONLY credential (1005)." }, "429": { "description": "1003: the order bucket is exhausted, retryAfterMs." } }
      }
    },
    "/v1/chain/instructions": {
      "post": {
        "tags": ["DLT Market"], "operationId": "submitChainInstruction", "summary": "Submit an instruction signed by an external wallet's own key",
        "description": "2.32.0. WalletRegister (class External, memberId = you as sponsor), Lock (free to trading; credits your engine balance at finality) or Transfer, with signerKey and signature (DER ECDSA P-256 over SHA-256 of \"KXC:instr:\" and the canonical body). 200 with the status; poll GET /chain/v1/instructions/{hash}. 2.35.0 (revision 3.70): memberId must be your own member id (5003 otherwise) and the venue registrar co-signs the registration on your submission, which is your attestation of the professional flag; the body carries clientRef (the custody wallet id of your client the wallet trades for, optional) in place of a client identifier; the canonical body is schema 2 (section 6i); an envelope already final on the chain answers 5003 DuplicateInstruction with its Final status and is never applied twice, a body the chain refused at an earlier block may be posted again, the timestamp must lie within the venue's validity window.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainInstructionRequest" },
          "examples": {
            "lockShapeSignedBySdk": { "summary": "1. The SHAPE of a Lock envelope (does not execute as pasted: the signature must be computed by the SDK)", "description": "signerKey and signature are placeholders here: the SDK signs SHA-256(\"KXC:instr:\" || canonical body) with the wallet's own P-256 key and stamps tsNanos inside the chain's validity window; pasting this body answers 5003 with chain.reason.", "value": { "kind": "Lock", "auth": "WalletKey", "from": "9f3a21bc00d14e770000000000000000000000000000000000000000000000ab", "isin": "XS0000000777", "units": 100, "signerKey": "<the wallet's public key, hex>", "signature": "<DER ECDSA P-256 over the canonical body, hex>" } }
          } } } },
        "responses": { "200": { "description": "{ chain: { txHash, kind, state, height, reason } }, NOT the standard envelope.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainInstructionResult" } } } }, "400": { "description": "2013 with msg (an unreadable body) or with error naming the field (unknown kind, auth, walletClass or actionKind); 5003 with error = the chain's refusal and chain (state Rejected, reason)" }, "403": { "description": "READ_ONLY credential (1005)." }, "429": { "description": "1003: the order bucket is exhausted, retryAfterMs." } }
      }
    },
    "/v1/chain/settlements": {
      "get": {
        "tags": ["DLT Market"], "operationId": "getChainSettlements", "summary": "Your settlement obligations",
        "description": "2.32.0. One row per fill on a SECURITY market: tradeId, engineSeqNo, isin, units, state (Pending | Settled | Failed), height, txHash, houseCoveredUnits, reason, observedUtcMs, settledUtcMs. ?tradeId= for one, ?state= to filter, ?limit= up to 1000.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "tradeId", "in": "query", "schema": { "type": "integer", "format": "int64" } },
          { "name": "state", "in": "query", "schema": { "type": "string", "enum": ["Pending", "Settled", "Failed"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer" } }
        ],
        "responses": { "200": { "description": "A bare ARRAY of settlement rows (NOT the standard envelope; 2.35.0: typed as served); with ?tradeId= one row as an object, or 404 when the trade is not yours.", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ChainSettlement" } } } } } }
      }
    },
    "/chain/v1/head": {
      "get": {
        "tags": ["DLT Market"], "operationId": "getChainHead", "summary": "Public record: the chain head",
        "description": "2.32.0. No authentication. height, blockHash, stateRoot, validators, quorum, headSignatures, unattestedTail, tokens, wallets, settledTrades, finality latency; since 2.35.0 (revision 3.70) externalValidators (the validators of the set in force not operated by the venue operator, beside requireExternal, the configured rule; /chain/v1/validators carries it too) and headValidators plus headQuorum (the size and the quorum of the set that signed the head block, which headSignatures counts against; validators and quorum describe the next block). A route that takes a hash answers 400 (must be 64 hex digits) on anything but 64 hex digits, 0x allowed, and 404 on a well-formed hash it does not hold. The same public API serves /chain/v1/blocks, /chain/v1/blocks/{height}, /chain/v1/tx/{hash} (Merkle inclusion proof), /chain/v1/tokens, /chain/v1/tokens/{isin} (integrity of issue), /chain/v1/wallets/{id}, /chain/v1/wallets/{id}/proof?isin=, /chain/v1/validators, /chain/v1/integrity, /chain/v1/settlements, /chain/v1/instructions/{hash} and, since 2.34.0, /chain/v1/valuation (served from the venue's last evaluation, the 60 s sweep's or a refresh at most one second old, revision 3.70; the Article 3 figures of Regulation (EU) 2022/858: every instrument's valuation at the closing or opening auction price, else the last trade, else the mark, in EUR at the ECB reference rate, the aggregate market value against the admission cap and the transition figure, the status OK, WATCH, ADMISSION_CAP or TRANSITION, and since 2.35.0 monthlyAverage, the frozen Article 3(4) average of the last complete month with month, days, aggregateEur, status and perIsin[], null while fewer than one complete month is recorded, plus monthlyAverageRule, and the flat twins monthlyAverageEur and monthlyAverageMonth beside dailyAggregateReachesTransition, a one-day spike above the transition figure reported and never acted on: the transition follows the monthly average); wallets are key hashes and no member or client identity is on the public record. 2.35.0 (revision 3.70): a frozen wallet reads status Frozen and a frozen instrument status Frozen with frozenBy REGISTRAR or ISSUER, and nothing else about the measure (no ground, no case reference); orders, amends, RFQ requests and quotes for a frozen instrument or a frozen client custody wallet answer 2049 TOKEN_RESTRICTED before the engine.",
        "responses": { "200": { "description": "the head (no envelope; 2.35.0: typed as served)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChainHead" } } } }, "429": { "description": "per-peer rate limit" } }
      }
    },
    "/v1/market-segments": {
      "get": {
        "tags": ["Market Segments"], "operationId": "getMarketSegments", "summary": "Your counterparty acceptance configuration",
        "description": "Read this before every write. data.version is the value the PUT below needs: it is not optional in effect, it increments on every successful write, and a stale one rejects with 4001. 2.29.0: with ?symbol= the read is that market's per-market layer (its own version); without it the account configuration plus every per-market layer you hold under markets.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" }, "example": "BTC-USD-PERP",
            "description": "2.29.0: read the per-market layer of this market instead of the account configuration. Unknown symbol: 2001." }
        ],
        "responses": { "200": { "description": "OK. data is { restricted, allow, version }; carry version into your next PUT.",
          "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/MarketSegmentsConfig" } } }
          ] } } } } }
      },
      "put": {
        "tags": ["Market Segments"], "operationId": "replaceMarketSegments", "summary": "Replace your configuration",
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" }, "example": "BTC-USD-PERP",
            "description": "2.29.0: replace your PER-MARKET layer on this market instead of the account configuration (send that layer's version, from GET /v1/market-segments?symbol=). A layer only ever narrows: on that market a counterparty must be admitted by the account configuration of both sides and by the market layers of both sides. Unknown symbol: 2001." }
        ],
        "description": "THIS CHANGES WHO YOU CAN TRADE WITH, and it REPLACES your configuration rather than patching it. GET /v1/market-segments first, decide the whole configuration you want to end up with, and send it back with the version that GET just returned. Optimistic concurrency on version: a mismatch returns 4001 and changes nothing, and because every successful write increments the version, a version copied from an example is correct at most once. Restricting yourself narrows both what you match with on the book and which RFQs you can see and quote.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "requestBody": { "required": true, "content": { "application/json": {
          "schema": { "$ref": "#/components/schemas/MarketSegmentsRequest" },
          "examples": {
            "openToEveryMember": {
              "summary": "1. Accept every member (needs YOUR version from GET, not the 0 below)",
              "description": "The safe shape: it clears any restriction and returns you to the state a member starts in, so it can only ever widen who you trade with. It is nonetheless the one prefilled body on this page that does NOT execute as it stands unless you have never written this configuration, because version is optimistic concurrency and the 0 below is a placeholder for the reader, not a value to send. 0 is the version of a member that has NEVER configured Market Segments; every successful write increments it, so read GET /v1/market-segments, copy the version it returns into this body, and send it within the same working session. Sending a stale version returns 4001 and changes nothing, which is the harmless failure and is exactly what the unedited body below does on any member that has written its configuration once.",
              "value": { "restricted": false, "allow": [], "version": 0 }
            },
            "restrictToNamedMembers": {
              "summary": "2. Accept only named members (CHANGES YOUR TRADING, and needs YOUR version)",
              "description": "Sending this narrows your counterparties to the listed member codes and nothing else, on the book and in RFQ alike. The codes below are sandbox members and exist only there; supply the codes you have actually agreed with, since an unrecognised code rejects the whole request with 5003 and changes nothing. version carries the same rule as example 1: send the one GET /v1/market-segments just returned, not the 0 below.",
              "value": { "restricted": true, "allow": ["SANDBOX-MM"], "version": 0 }
            }
          }
        } } },
        "responses": { "200": { "description": "OK. data.version is the new version; use it on your next write.",
          "content": { "application/json": { "schema": { "allOf": [
            { "$ref": "#/components/schemas/Envelope" },
            { "type": "object", "properties": { "data": { "type": "object", "properties": {
              "version": { "type": "integer", "example": 4, "description": "The new configuration version; send exactly this value on your next write." },
              "symbol": { "type": "string", "nullable": true, "example": "BTC-USD-PERP", "description": "2.29.0: the market of the per-market layer you replaced (?symbol=); null on the account configuration. Documented in the schema since 2.31.0." }
            } } } }
          ] } } } },
          "400": { "description": "Unknown member code in allow (5003), or a missing body or a null allow (2013, the body must carry an array, empty or not): nothing is changed." },
          "409": { "description": "Version conflict (4001): the version you sent is not the current one and nothing was changed." } }
      }
    },
    "/v1/market-segments/matchable-members": {
      "get": {
        "tags": ["Market Segments"], "operationId": "getMatchableMembers", "summary": "Member codes you can currently match with",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "schema": { "type": "string" }, "example": "BTC-USD-PERP",
            "description": "2.29.0: the codes you can match with ON THIS MARKET (the account configuration of both sides and the market layers of both sides); without it the account-level relation. Unknown symbol: 2001." }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "string" }, "example": ["SANDBOX-MM"],
            "description": "Member codes both sides of the Market Segments configuration allow." } } }
        ] } } } } }
      }
    },
    "/v1/orderbook/matchable": {
      "get": {
        "tags": ["Market Segments"], "operationId": "getMatchableOrderBook", "summary": "Your matchable book: rows are [price, matchableQty, ownQty]",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "symbol", "in": "query", "required": true, "schema": { "type": "string" }, "example": "BTC-USD-PERP" },
          { "name": "depth", "in": "query", "schema": { "type": "integer", "enum": [1, 5, 25, 100] }, "example": 5 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Book" } } }
        ] } } } } }
      }
    },
    "/v1/adl/indicator": {
      "get": {
        "tags": ["Risk"], "operationId": "getAdlIndicator", "summary": "Your auto-deleveraging queue quintile per position",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [{ "name": "symbol", "in": "query", "schema": { "type": "string" } }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "type": "object", "properties": {
            "symbol": { "type": "string", "example": "BTC-USD-PERP" },
            "adlQuintile": { "type": "integer", "example": 2, "description": "1 to 5; open positions only. 5 = first to be auto-deleveraged; rank by unrealized profit ratio multiplied by account leverage, highest first, ties by ascending member id; recomputed every 5 seconds." }
          } } } } }
        ] } } } } }
      }
    },
    "/v1/adl/events": {
      "get": {
        "tags": ["Risk"], "operationId": "getAdlEvents", "summary": "Auto-deleveraging allocations affecting you, newest first",
        "description": "2.35.0: documented for the first time (served since the venue's projections existed). One row per auto-deleveraging allocation the venue recorded for you, newest first, from the venue's projections (the envelope asOfSeq is the store watermark). As the DEFAULTER of an episode you see every slice of that episode, your own per-client rows included (role DEFAULTER, your clientUid, closeSide the direction the venue closed that client in; emitted from the engine sequence venue operations announce on the sandbox and from genesis on production), and the slices taken from other members with their clientUid withheld (no end-client identifier crosses members); as a deleveraged member you see your own allocations (role DELEVERAGED, your clientUid, closeSide your close direction). side is your relation to the EPISODE (DEFAULTER or COUNTERPARTY), role is the row's attribution: on the defaulter's own rows both read DEFAULTER. Rows recorded before this revision carry role DELEVERAGED (every one of them a counterparty row) and no closeSide. The same rows reach you live on the WebSocket adl channel (type execution, cursor-backfillable, Member API sections 10 and 11).",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "parameters": [
          { "name": "from", "in": "query", "description": "Earliest ts, Unix ms, inclusive.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "to", "in": "query", "description": "Latest ts, Unix ms, inclusive.", "schema": { "type": "integer", "format": "int64" } },
          { "name": "limit", "in": "query", "description": "Bounds the list.", "schema": { "type": "integer", "minimum": 1, "maximum": 1000, "default": 100 }, "example": 100 }
        ],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/AdlEventRow" } } } }
        ] } } } },
          "429": { "description": "Rate limit (1003): the read bucket, or, since 2.37.0, more reads of yours in flight on this route group than the node serves at once, or the node's budget of these reads, which every member shares, full (data.retryAfterMs, a suggested wait, and Retry-After; a 1003 while no other read of yours of the group is in flight is the shared budget's, which serialising cannot help: back off)." },
          "503": { "description": "Since 2.37.0, the venue's history store did not answer in time or is busy (5007: retry after data.retryAfterMs, Retry-After); nothing changed on your account." } }
      }
    },
    "/v1/unwinds": {
      "get": {
        "tags": ["Risk"], "operationId": "getUnwinds", "summary": "Liquidation and auto-deleveraging episodes affecting you",
        "description": "As defaulter you see the full episode; as counterparty you see your own allocations. Your own end clients' split of an auto-deleveraging is on GET /v1/adl/events and the adl channel, not here.",
        "security": [{ "ApiKey": [], "Timestamp": [], "Signature": [] }],
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "allOf": [
          { "$ref": "#/components/schemas/Envelope" },
          { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/UnwindEpisode" } } } }
        ] } } } } }
      }
    }
  }
}