# ╔══════════════════════════════════════════════════════════════════════════╗ # ║ GENERATED FILE — DO NOT EDIT BY HAND. ║ # ║ Source of truth: the per-service markdown in docs/exchange/api/. ║ # ║ Regenerate: python3 docs/exchange/api/tools/gen_openapi.py ║ # ╚══════════════════════════════════════════════════════════════════════════╝ openapi: 3.1.0 info: title: Sphinx Exchange — Edge API version: 0.16.0 summary: Custodial, crypto-settled prediction-market exchange — public REST + WSS surface. description: 'The Edge API is the public surface of Sphinx Exchange. It speaks Kalshi-compatible vocabulary over REST and WebSocket; under the hood, every order is sequenced by an Aeron Cluster deterministic core, matched by an in-memory C++ engine, and audited into ClickHouse — see `docs/exchange/exchange_software_design.md` for the architecture. This spec covers V0 and V0.1 (in-process MockChain custody, single-node sequencer, operator-attested resolution authority). See `docs/exchange/api/README.md` for the human-readable docs, change process, and codegen instructions. This file is GENERATED from the per-service markdown in `docs/exchange/api/services/` by `tools/gen_openapi.py` — edit the markdown, not this file. The margin-era (derivatives) surface is included here: the margin `/v1/snapshot` block, `/v1/margin_info`, `/v1/insurance_fund`, `/v1/liquidation_metrics`, `/v1/contract_spec(s)`, the `reduce_only` / `post_only` order flags, and the mark / account WebSocket channels — behavior normative in `docs/exchange/exchange_derivatives_engine_spec.md` §14. Projection vs engine state: engine-state fields (balances, `signed_qty`, the `margin` block, marks, `last_settlement_price` = the SV-2 basis) reconcile bit-for-bit against the engine at one `engine_seq_applied`; the average entry price is an Edge PROJECTION off the fill tape (`GET /v1/fills`), never an engine field — do not conflate the two. EXTERNAL VARIANT: operator-only (`x-internal`) operations are omitted.' termsOfService: https://sphx.io/terms contact: name: Sphinx Exchange Engineering url: https://github.com/sphx-io email: api@sphx.io license: name: Proprietary identifier: LicenseRef-Sphinx-Proprietary servers: - url: https://api.staging.sphx.io description: Staging — LIVE (always-on demo venue; signup faucet enabled) - url: https://api.sphx.io description: Production (placeholder; not yet deployed) - url: http://127.0.0.1:18201 description: Local development (services brought up via `make up`) tags: - name: Accounts description: Account registration, profile lookup. - name: Credentials description: API key management. Customers may issue, list, and revoke their own credentials. - name: Auth description: Email+password sessions for outside users. Signup/login mint a short-lived session credential and return the same `.` bearer API keys use; logout revokes it. - name: Orders description: Place, cancel, and list open orders. - name: Market Data description: Instruments, order books, balances, positions, fills. - name: Candles description: OHLCV candle bars for charting (multiple resolutions). - name: Custody description: Deposit address allocation and withdrawal lifecycle. - name: Margin description: Margin sub-account cash transfers and margin-state projections. - name: Instrument description: Instrument lifecycle (read) and reporter resolution submission. - name: WebSocket description: Real-time push channels. Documented as one operation for codegen visibility; the wire protocol is in `docs/exchange/api/services/websockets.md`. - name: Operations description: Service health and metrics, served on a separate port (8080 in dev). - name: Power description: Reference prices for the venue's power markets (ERCOT hubs and load zones). Not an index or settlement input. security: - {} externalDocs: description: Human-readable API documentation url: https://github.com/sphx-io/docs/blob/main/exchange/api/README.md components: securitySchemes: BearerAuth: type: http scheme: bearer description: 'Customer-facing authentication. Use the `plaintext_key` returned by `POST /v1/accounts` or `POST /v1/credentials` as the bearer token. Tokens have the shape `.` where the prefix is the credential''s public identifier (used as a database lookup key) and the suffix is a high-entropy secret. Edge validates by looking up the credential by prefix and verifying SHA-256 of the suffix against the stored hash. ' ReporterKey: type: apiKey in: header name: X-Reporter-Key description: 'Reporter authentication for `/v1/instrument/resolution/*` (submit + preview). Dev value is the literal string `dev-reporter` (configurable via `EDGE_REPORTER_API_KEY`). V0 is a single shared secret; V1 introduces reporter quorum (each reporter has its own key + stake). ' parameters: PathInstrumentID: name: instrument_id in: path required: true schema: type: integer format: int64 minimum: 1 description: The instrument ID. PathOrderID: name: order_id in: path required: true schema: type: integer format: int64 minimum: 1 description: The order ID. PathWithdrawalID: name: withdrawal_id in: path required: true schema: type: integer format: int64 minimum: 1 description: The withdrawal ID. PathCredentialID: name: credential_id in: path required: true schema: type: integer format: int64 minimum: 1 description: The credential ID. responses: BadRequest: description: 'Request was malformed or failed validation. The `error.code` field carries the machine-readable reason; common values include `invalid_request`, `invalid_json`, `invalid_order_id`, `invalid_instrument_id`, `invalid_credential_id`, `invalid_resolution`, and operation-specific codes documented per endpoint. ' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: invalid_request: value: error: code: invalid_request message: amount must be positive correlation_id: 8c2c0e9a-3... Unauthorized: description: Missing or invalid `Authorization` header. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: unauthorized: value: error: code: unauthorized message: missing or invalid bearer token correlation_id: 8c2c0e9a-3... Forbidden: description: Authentication succeeded but the action is not permitted. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: forbidden: value: error: code: forbidden message: admin key required correlation_id: 8c2c0e9a-3... NotFound: description: The named resource does not exist (or belongs to another account). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' Conflict: description: 'The request conflicts with existing state. The `error.code` field carries the machine-readable reason (e.g. `email_taken` on signup). ' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: email_taken: value: error: code: email_taken message: an account with this email already exists correlation_id: 8c2c0e9a-3... RateLimited: description: Too many attempts inside the fixed rate-limit window (10 attempts / 5 minutes per key). Retry in a few minutes. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: rate_limited: value: error: code: rate_limited message: too many attempts; retry in a few minutes correlation_id: 8c2c0e9a-3... InternalError: description: Unexpected server error. Includes a `correlation_id`; report it when filing a bug. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' ServiceUnavailable: description: A required downstream (matching engine, ClickHouse, custody, instrument service) is unreachable. The request was not processed; retry with backoff. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' examples: CreateAccountResponse: summary: A freshly-registered account value: data: account: account_id: 7 state: active entitlement_mask: 15 default_subaccount: 0 handle: alice created_at_ns: 1779108879000000000 initial_credential: credential_id: 7 account_id: 7 prefix: 0167a3... entitlement_mask: 15 label: initial created_at_ns: 1779108879100000000 plaintext_key: 0167a3....6f4c8d99a4b2e... correlation_id: a17d-… PlaceOrderRested: summary: Limit order that rests on the book value: data: order_id: 42 sequencer_correlation_id: 17 status: accepted_rested filled_count: 0 resting_count: 100 side: 'yes' action: buy order_type: limit price_pips: 5500 count: 100 edge_received_at_ns: 1779000000123456 sequencer_committed_at_ns: 1779000000456789 engine_applied_at_ns: 1779000000789012 correlation_id: a17d-… PlaceOrderFullyFilled: summary: Limit order that fully matches value: data: order_id: 43 sequencer_correlation_id: 18 status: accepted_fully_filled filled_count: 100 resting_count: 0 side: 'yes' action: sell order_type: limit price_pips: 5500 count: 100 edge_received_at_ns: 1779000000123456 sequencer_committed_at_ns: 1779000000456789 engine_applied_at_ns: 1779000000789012 correlation_id: a17d-… schemas: Envelope: type: object description: 'Every JSON response wraps its payload in this envelope. Successful responses set `data` to the operation''s payload; error responses use `ErrorEnvelope` instead. `correlation_id` echoes the request''s correlation ID and is the key reference for debugging — include it in any support ticket. ' required: - correlation_id properties: correlation_id: type: string description: Per-request correlation ID (UUID v4 unless the client overrode it via the `X-Correlation-ID` header). examples: - 8c2c0e9a-3...-... ErrorEnvelope: type: object required: - error - correlation_id properties: error: $ref: '#/components/schemas/Error' correlation_id: type: string examples: - 8c2c0e9a-3...-... Error: type: object required: - code - message properties: code: type: string description: Machine-readable error category. See the docs `error code` table for all values. examples: - invalid_request - unauthorized - insufficient_funds message: type: string description: Human-readable error description, safe to surface to operators. details: description: Optional, operation-specific structured detail. AccountState: type: string description: "Account lifecycle state.\n - `pending` — account exists, awaiting activation (KYC,\ \ etc.)\n - `active` — full trading + deposit + withdrawal\n - `trade_frozen` — withdrawals\ \ allowed, no new trades\n - `withdraw_frozen` — trades allowed, no new withdrawals\n - `fully_frozen`\ \ — read-only\n - `closed` — terminal; account is gone\n" enum: - pending - active - trade_frozen - withdraw_frozen - fully_frozen - closed OrderSide: type: string description: "Which side of the binary market this order is on.\n - `yes` — bid/ask on the YES\ \ contract\n - `no` — bid/ask on the NO contract (a SELL YES is also expressible as a BUY NO\ \ at 10000 - price)\n" enum: - 'yes' - 'no' InstrumentState: type: string description: "Lifecycle state of an instrument (engine view).\n - `trading` — open for orders\n\ \ - `pending` — closed for new orders, awaiting resolution\n - `reported` — outcome submitted\ \ (V1: dispute window open)\n - `disputed` — under review (V1)\n - `final` — resolved + settled\n" enum: - trading - pending - reported - disputed - final Instrument: type: object description: Full instrument metadata as managed by the Instrument service. required: - instrument_id - resolution_criterion - max_payoff_pips - state - created_at_ns properties: instrument_id: type: integer format: int64 resolution_criterion: type: string description: Human-readable criterion the reporter attests against ("Will event X happen by date Y?"). closes_at_ns: type: integer format: int64 description: Trading closes at this timestamp; 0 means manually advanced by operator. max_payoff_pips: type: integer format: int32 description: Maximum payoff per contract in pips. Binary YES/NO uses 10000 (= $1.00). state: type: integer format: int32 description: Numeric lifecycle state (0=LISTED, 1=TRADING, 2=PENDING, 3=REPORTED, 4=DISPUTED, 5=FINAL). minimum: 0 maximum: 5 resolved_outcome_pips: type: integer format: int32 description: Set once FINAL. 10000 = YES outcome, 0 = NO outcome. created_at_ns: type: integer format: int64 handle: type: string DepositAddress: type: object required: - account_id - asset_id - chain_id - address - created_at_ns properties: account_id: type: integer format: int64 asset_id: type: integer format: int32 chain_id: type: integer format: int32 address: type: string description: Chain-native address (Solana base58 in V1+). created_at_ns: type: integer format: int64 WithdrawalState: type: string description: "Withdrawal lifecycle.\n - `pending_finality` — accepted by Edge, awaiting custody-coordinator\ \ pickup\n - `broadcast` — chain transaction submitted, awaiting confirmation\n - `finalized`\ \ — confirmed on-chain\n - `failed` — terminal failure (insufficient funds at signer, RPC reject,\ \ etc.).\n Defined terminal state, but NEVER reached in V0/V0.1 (the in-process MockChain\n\ \ always succeeds and finalizes instantly); real failure paths arrive with Solana\n custody\ \ in V1.7.\n" enum: - pending_finality - broadcast - finalized - failed CreateWithdrawalRequest: type: object required: - amount - address properties: asset_id: type: integer format: int32 default: 1 description: Defaults to 1 (USDC). amount: type: integer format: int64 minimum: 1 description: Atomic units (USDC has 6 decimals). address: type: string description: Destination chain address. Withdrawal: type: object required: - withdrawal_id - account_id - asset_id - amount - state - submitted_at_ns properties: withdrawal_id: type: integer format: int64 account_id: type: integer format: int64 asset_id: type: integer format: int32 chain_id: type: integer format: int32 amount: type: integer format: int64 destination_address: type: string state: $ref: '#/components/schemas/WithdrawalState' chain_txn_sig: type: string description: Chain transaction signature (set once broadcast). submitted_at_ns: type: integer format: int64 broadcast_at_ns: type: integer format: int64 finalized_at_ns: type: integer format: int64 sequencer_correlation_id: type: integer format: int64 status: type: string description: Convenience alias for `state` returned only on the initial POST response (`pending_finality`). Account: type: object required: - account_id - state - entitlement_mask - default_subaccount - created_at_ns properties: account_id: type: integer format: int64 state: $ref: '#/components/schemas/AccountState' entitlement_mask: type: integer format: int64 description: "Bitmask of entitlements granted to this account's credentials. Bits:\n 1 (TradeEnabled),\ \ 2 (WithdrawEnabled), 4 (DepositEnabled), 8 (APITrading).\nV0 default is 15 (all four).\n" default_subaccount: type: integer format: int32 default: 0 handle: type: string description: Optional display handle chosen at registration. created_at_ns: type: integer format: int64 email: type: string description: Login e-mail — present only on `GET /v1/accounts/me` for password accounts. email_verified: type: boolean description: '0.9.0: whether the login e-mail has been proven (confirmation link, password reset, or operator verify). Present only for password accounts, only on `GET /v1/accounts/me`. ' Credential: type: object required: - credential_id - account_id - prefix - entitlement_mask - created_at_ns properties: credential_id: type: integer format: int64 account_id: type: integer format: int64 prefix: type: string description: Public credential identifier (the part before the `.` in the Bearer token). entitlement_mask: type: integer format: int64 label: type: string description: Operator-chosen label for this credential (e.g. "frontend", "backtest-bot"). created_at_ns: type: integer format: int64 expires_at_ns: type: integer format: int64 description: Expiry timestamp (0 = no expiry). scope: $ref: '#/components/schemas/CredentialScope' agent: $ref: '#/components/schemas/AgentDescriptor' daily: type: object description: 0.16.0 — today's accepted notional and order count for API keys (absent on sessions and when the ledger is unavailable); the Agents tab's budget meter against `scope.max_daily_notional_uusdc`. required: - day_utc - notional_used_uusdc - orders - notional_cap_uusdc properties: day_utc: type: string notional_used_uusdc: type: integer format: int64 orders: type: integer format: int64 notional_cap_uusdc: type: integer format: int64 plaintext_key: type: string description: '**The full Bearer token, returned exactly once at creation time.** Subsequent calls to `GET /v1/credentials` will NOT include this field. Store immediately. ' CredentialScope: type: object required: - instrument_allowlist - max_order_notional_uusdc - max_daily_notional_uusdc - max_open_orders - approval_mode properties: instrument_allowlist: type: array items: type: integer format: int64 description: Empty = every instrument. max_order_notional_uusdc: type: integer format: int64 description: 0 = no cap. max_daily_notional_uusdc: type: integer format: int64 description: 0 = no cap. max_open_orders: type: integer description: 0 = no cap. Counts the account's resting orders at placement. approval_mode: type: string enum: - auto - require_human AgentDescriptor: type: object additionalProperties: true properties: name: type: string description: Short agent name; appears as `agent` on the credential's fills. model: type: string description: The model or runtime driving the agent, e.g. claude-sonnet-5. operator: type: string description: Who runs the agent. DeadmanRequest: type: object required: - ttl_ms properties: ttl_ms: type: integer format: int64 description: 1000..300000 arms or refreshes the switch; 0 disarms. DeadmanState: type: object required: - armed - ttl_ms - expires_at_ns - fired_count - last_fired_at_ns properties: armed: type: boolean ttl_ms: type: integer format: int64 description: Armed TTL; 0 when disarmed. expires_at_ns: type: integer format: int64 description: When the switch fires unless refreshed; 0 when disarmed. fired_count: type: integer description: Times the switch has fired for this account since the edge started. last_fired_at_ns: type: integer format: int64 description: 0 if never fired. AccountLimits: type: object required: - credential_id - write properties: credential_id: type: integer format: int64 write: type: object required: - enabled properties: enabled: type: boolean description: False when the venue has not enabled the write limiter (no headers are sent). limit: type: integer description: Writes allowed per window. window_s: type: integer format: int64 remaining: type: integer reset_at_ns: type: integer format: int64 scope: $ref: '#/components/schemas/CredentialScope' daily: type: object description: Today's consumption of the credential's daily cap (0.14.0). Absent when the ledger is unavailable. required: - day_utc - notional_used_uusdc - orders - notional_cap_uusdc properties: day_utc: type: string description: The UTC day the ledger covers (YYYY-MM-DD). notional_used_uusdc: type: integer format: int64 orders: type: integer format: int64 description: Accepted orders today. notional_cap_uusdc: type: integer format: int64 description: The credential's `max_daily_notional_uusdc` (0 = none). agent: $ref: '#/components/schemas/AgentDescriptor' CreateAccountRequest: type: object properties: handle: type: string description: Optional display handle. CreateAccountResponse: type: object required: - account - initial_credential properties: account: $ref: '#/components/schemas/Account' initial_credential: $ref: '#/components/schemas/Credential' CreateCredentialRequest: type: object properties: label: type: string description: Display label for the credential. entitlement_mask: type: integer format: int64 description: Bitmask. Defaults to the calling credential's mask if omitted. expires_in_s: type: integer format: int64 minimum: 0 maximum: 31622400 description: Seconds until the credential expires (0.11.0). 0 / omitted = never. Max 366 days. instrument_allowlist: type: array maxItems: 64 items: type: integer format: int64 description: Scope (0.14.0). Instruments this credential may trade; empty / omitted = all. Cancels are never restricted. max_order_notional_uusdc: type: integer format: int64 minimum: 0 description: Scope (0.14.0). Per-order notional cap in µUSDC; 0 = none. max_daily_notional_uusdc: type: integer format: int64 minimum: 0 description: Scope (0.14.0). Accepted-order notional per UTC day, µUSDC; 0 = none. Durable across edge restarts. max_open_orders: type: integer minimum: 0 maximum: 10000 description: Scope (0.14.0). Refuse new orders while the account has this many resting; 0 = none. approval_mode: type: string enum: - auto - require_human description: Scope (0.14.0). `require_human` parks every order for a human to approve (POST /v1/orders → 202). agent: $ref: '#/components/schemas/AgentDescriptor' SignupRequest: type: object required: - email - password properties: email: type: string format: email description: Login identifier; lowercased and trimmed server-side. One account per email. password: type: string minLength: 10 maxLength: 128 description: Stored as argon2id (PHC format); never returned. handle: type: string description: Optional display handle. Defaults to the email's local part. LoginRequest: type: object required: - email - password properties: email: type: string format: email password: type: string SessionResponse: type: object required: - account - session_token - expires_at_ns - email_verified properties: account: $ref: '#/components/schemas/Account' session_token: type: string description: 'The session bearer for `Authorization: Bearer` — same `.` format as API keys. **Returned exactly once**; store it immediately. ' expires_at_ns: type: integer format: int64 description: Session expiry timestamp (nanoseconds since epoch). Sessions live 7 days. faucet_uusdc: type: integer format: int64 description: 'Signup only, faucet-enabled venues only (dev/staging): the µUSDC credit being sequenced asynchronously — balances appear within a few seconds. Omitted when the faucet is disabled and on login. ' email_verified: type: boolean description: '0.9.0: whether the account e-mail is proven. `false` right after signup (a confirmation link was e-mailed), `true` after confirmation, on login for a verified account, and always after a password reset. ' confirmation: type: string enum: - sent - failed description: 'Signup only (0.9.0): whether the confirmation link reached the mail relay. The link exists either way — `POST /v1/auth/confirm/resend` re-sends. ' LogoutResponse: type: object required: - status properties: status: type: string enum: - logged_out TokenRequest: type: object required: - token properties: token: type: string description: The value after `?confirm=` (or `?reset=`) in the e-mailed link. Single use. ConfirmResponse: type: object required: - account_id - email_verified properties: account_id: type: integer format: int64 email_verified: type: boolean ResendResponse: type: object required: - email_verified - delivery properties: email_verified: type: boolean delivery: type: string enum: - sent - failed - not_needed ForgotPasswordRequest: type: object required: - email properties: email: type: string format: email AcceptedResponse: type: object required: - status properties: status: type: string enum: - accepted ResetPasswordRequest: type: object required: - token - new_password properties: token: type: string description: The value after `?reset=` in the e-mailed link. Single use, 30-minute expiry. new_password: type: string minLength: 10 maxLength: 128 ChangePasswordRequest: type: object required: - current_password - new_password properties: current_password: type: string new_password: type: string minLength: 10 maxLength: 128 ChangePasswordResponse: type: object required: - status - other_sessions_revoked properties: status: type: string enum: - changed other_sessions_revoked: type: integer format: int64 PreviewResolutionResponse: type: object required: - instrument - has_index_value - note properties: instrument: $ref: '#/components/schemas/Instrument' has_index_value: type: boolean description: Whether the price component has a journaled selected index value for this instrument. index_value_uusdc: type: integer format: int64 description: The last selected index value (micro-USDC). Present when has_index_value. index_slot_ts_ns: type: integer format: int64 description: The slot instant the value was selected for (epoch-aligned Unix ns). index_published_at_ns: type: integer format: int64 description: Wall-clock journal time of the publication (diagnostic). staleness_ns: type: integer format: int64 description: now − index_slot_ts_ns at preview time. Advisory staleness signal. note: type: string description: Advisory disclaimer — the engine derives b′ outcomes authoritatively from sequenced state. MarginMetadata: type: object description: 'Identity/display record for a listed margined instrument, recorded at listing time. base/quote/expiry_date derive from price_feed_id; symbol is unique venue-wide. Economics live in the ContractSpec projection. ' required: - instrument_id - symbol - display_name - base - quote - product_class - price_feed_id - listed_at_ns - contract_size - unit properties: instrument_id: type: integer format: int64 symbol: type: string description: Unique display symbol, e.g. BTC-USD-PERP / BTC-USD-20260926. display_name: type: string base: type: string description: Base asset from the feed grammar, e.g. "btc". quote: type: string description: Quote asset from the feed grammar, e.g. "usd". product_class: type: integer description: 0 = perpetual, 1 = expiring future. price_feed_id: type: string description: The data-oracle index feed named at listing (manifest record). expiry_date: type: string description: YYYYMMDD from a fut-dated feed id; omitted otherwise. Display hint — the engine's expiry_datetime_utc_ns is authoritative. listed_at_ns: type: integer format: int64 contract_size: type: integer description: Units of `unit` one contract delivers (0.7.0); 1 for every current listing. unit: type: string description: Physical unit one contract is denominated in, e.g. MWh, BTC (0.7.0). SubmitResolutionRequest: type: object required: - instrument_id - outcome_pips properties: instrument_id: type: integer format: int64 outcome_pips: type: integer format: int32 enum: - 0 - 10000 description: 10000 = YES outcome, 0 = NO outcome. evidence_ref: type: string description: URL or hash pointing at supporting evidence. reporter_id: type: integer format: int64 description: V0 ignores this (single shared reporter key); V1 uses it for quorum. SubmitResolutionResponse: type: object required: - instrument - submission_id properties: instrument: $ref: '#/components/schemas/Instrument' submission_id: type: integer format: int64 FundingPage: type: object required: - funding - next_cursor properties: funding: type: array items: $ref: '#/components/schemas/FundingRate' next_cursor: type: - string - 'null' description: Pass back as `cursor` for the next (older) page; null when no more. FundingRate: type: object required: - event_seq - ts_ns - instrument_id - boundary_ns - rate_fp8 - premium_fp8 - interest_fp8 - skipped properties: event_seq: type: integer format: int64 ts_ns: type: integer format: int64 description: Cluster timestamp — milliseconds despite the name. instrument_id: type: integer format: int64 boundary_ns: type: integer format: int64 description: The funding boundary instant (Unix nanoseconds). rate_fp8: type: integer format: int64 description: Funding rate per interval, fixed-point 1e-8 (positive = longs pay). premium_fp8: type: integer format: int64 description: Premium TWAP component, fixed-point 1e-8. interest_fp8: type: integer format: int64 description: Interest component per interval, fixed-point 1e-8. skipped: type: boolean description: True for a degenerate boundary (rate 0, no payments). FeeSchedule: type: object required: - engine_seq_applied - fees properties: engine_seq_applied: type: integer format: int64 fees: type: array items: type: object required: - instrument_id - fee_model - maker_fee_rate_bps - taker_fee_rate_bps - maker_fee_flat_uusdc - taker_fee_flat_uusdc - funding_is_fee_free - delivery_fee_bps - delivery_fee_enabled properties: instrument_id: type: integer format: int64 fee_model: type: integer maker_fee_rate_bps: type: integer format: int32 description: Signed; negative = maker rebate. taker_fee_rate_bps: type: integer format: int32 maker_fee_flat_uusdc: type: integer format: int64 taker_fee_flat_uusdc: type: integer format: int64 funding_is_fee_free: type: boolean delivery_fee_bps: type: integer delivery_fee_enabled: type: boolean InstrumentSnapshot: type: object required: - instrument_id - state properties: instrument_id: type: integer format: int64 state: $ref: '#/components/schemas/InstrumentState' OpenInterestSnapshot: type: object required: - engine_seq_applied - rows properties: engine_seq_applied: type: integer format: uint64 description: Engine snapshot seq the rows were computed at. rows: type: array items: type: object required: - instrument_id - open_interest_contracts - open_interest_uusdc properties: instrument_id: type: integer format: int64 open_interest_contracts: type: integer format: int64 description: One-sided OI in contract units (Σ long qty). open_interest_uusdc: type: integer format: int64 description: One-sided OI in mark-notional µUSDC. Orderbook: type: object required: - instrument_id - yes_bids - no_bids properties: instrument_id: type: integer format: int64 yes_bids: type: array items: $ref: '#/components/schemas/OrderbookLevel' no_bids: type: array items: $ref: '#/components/schemas/OrderbookLevel' yes_asks: type: array description: Side-native margined SELLS (signed ticks, best ask first). Present on margined books only; event-class books keep the §11.9 no_bids complement form. items: $ref: '#/components/schemas/OrderbookLevel' OrderbookLevel: type: object required: - price_pips - count properties: price_pips: type: integer format: int32 minimum: 1 maximum: 9999 count: type: integer format: int32 minimum: 1 CandleResolution: type: string enum: - 1m - 5m - 15m - 1h - 1d Candle: type: object required: - t - o - h - l - c - v properties: t: type: integer format: int64 description: Bar start time (Unix seconds). o: type: integer format: int32 description: Open price (pips). h: type: integer format: int32 description: High price (pips). l: type: integer format: int32 description: Low price (pips). c: type: integer format: int32 description: Close price (pips). v: type: integer format: int64 description: Volume (contracts). closed: type: boolean description: '`true` when the bar window has elapsed and values are final. Omitted (or `false`) for the latest in-flight bar, which may update on the `candles` WSS channel. ' CandleSeries: type: object required: - instrument_id - resolution - side - bars properties: instrument_id: type: integer format: int64 resolution: $ref: '#/components/schemas/CandleResolution' side: $ref: '#/components/schemas/OrderSide' bars: type: array items: $ref: '#/components/schemas/Candle' VenueHealthResponse: type: object required: - status - books_two_sided - last_fill_age_s - disk_used_pct properties: status: type: string enum: - ok - unhealthy reasons: type: array description: Present when unhealthy — the failing checks. items: type: string enum: - books_one_sided - tape_stale - disk_pressure books_two_sided: type: integer description: Count of margined books currently quoted on both sides. last_fill_age_s: type: integer format: int64 description: Seconds since the venue's most recent fill. disk_used_pct: type: integer description: Root-disk usage percent on the venue host. ServiceStatusReport: type: object required: - status - checked_at - services properties: status: type: string enum: - ok - degraded - down checked_at: type: string format: date-time services: type: array items: type: object required: - name - status - latency_ms properties: name: type: string example: trading-engine status: type: string enum: - ok - down latency_ms: type: integer format: int64 detail: type: string description: Failure detail when down. PowerPrices: type: object required: - market - as_of_ns - points properties: market: type: string enum: - ercot as_of_ns: type: integer format: int64 description: Server time of this response (nanoseconds since epoch); the instant the `stale` flags were evaluated. points: type: array items: $ref: '#/components/schemas/PowerPoint' PowerPoint: type: object required: - point - kind - lmp - spp properties: point: type: string description: ERCOT settlement point name, e.g. `HB_NORTH`, `LZ_SOUTH`. kind: type: string enum: - hub - load_zone - hub_average lmp: description: Latest 5-minute SCED locational marginal price; `null` until first observed. oneOf: - $ref: '#/components/schemas/PowerPrice' - type: 'null' spp: description: Latest 15-minute real-time settlement point price (the RT perps' settlement basis); `observed_at_ns` is the interval-ending instant. `null` until first observed. oneOf: - $ref: '#/components/schemas/PowerPrice' - type: 'null' instrument_id: type: integer format: int64 description: The RT perpetual listed on this point, when there is one. symbol: type: string description: Display symbol of that perpetual. PowerPrice: type: object required: - value_uusdc - observed_at_ns - stale properties: value_uusdc: type: integer format: int64 description: Price in µUSDC per MWh (41370000 = $41.37/MWh). May be negative. observed_at_ns: type: integer format: int64 description: ERCOT's own timestamp for the value (nanoseconds since epoch), never the collection time. stale: type: boolean description: True when flagged invalid upstream or older than the freshness window (20 min LMP, 40 min SPP). The value is the last known price. OrderAction: type: string enum: - buy - sell OrderType: type: string enum: - limit - market TimeInForce: type: string description: "Order lifetime.\n - `gtc` — Good Till Cancelled (default)\n - `ioc` — Immediate\ \ Or Cancel (match what you can, cancel the rest)\n - `fok` — Fill Or Kill (match the whole thing\ \ or reject it)\n" enum: - gtc - ioc - fok OrderStatus: type: string description: "Engine outcome for an order.\n - `accepted_fully_filled` — entire quantity matched\n\ \ - `accepted_rested` — none matched immediately; on the book\n - `accepted_ioc_canceled` —\ \ partial match (or none) and IOC cancelled the rest\n - `rejected` — engine refused (see `reject_reason`)\n" enum: - accepted_fully_filled - accepted_rested - accepted_ioc_canceled - rejected OrderRejectReason: type: string description: 'Engine reject reason. The HTTP status mapping is documented per endpoint — balance/market reasons go to 422, account-state to 403, instrument-lifecycle to 409, validation to 400. ' enum: - invalid_price - invalid_quantity - invalid_max_cost - unknown_instrument - fok_would_not_fully_fill - max_cost_blocks_any_fill - market_no_liquidity - insufficient_funds - invalid_api_fields - stp_aborted - account_not_active - account_trade_frozen - instrument_halted - instrument_not_found - kill_switch_active - margined_requires_margin_sub - event_on_margin_sub - margined_limit_only - no_mark_yet - too_many_open_orders - account_notional_cap - venue_oi_cap - outside_price_band - reduce_only_would_increase - post_only_would_cross - instrument_reduce_only - circuit_breaker_halt - daily_notional_cap - unsupported_order_flags - fund_floor_open_block - unwind_rate_limit - one_sided_oi_cap - cancel_only_window - instrument_delist_pending STPQualifier: type: string description: 'Self-trade prevention. Only `cancel_newest` is supported in V0. ' enum: - cancel_newest OrderPreview: type: object required: - engine_seq_applied - instrument_id - margined - book - execution - fees - margin - would_reject - warnings properties: engine_seq_applied: type: integer format: int64 instrument_id: type: integer format: int64 margined: type: boolean book: $ref: '#/components/schemas/PreviewBook' execution: $ref: '#/components/schemas/PreviewExecution' fees: $ref: '#/components/schemas/PreviewFees' margin: oneOf: - $ref: '#/components/schemas/PreviewMargin' - type: 'null' description: Null for event contracts. would_reject: type: - string - 'null' description: Best-effort mirror of the engine's admission reject code, or null. Engine authoritative. warnings: type: array items: type: string description: e.g. max_cost_limits_fill, one_sided_or_empty_book. confirm_token: type: string description: Single-use, 60 s, bound to the order's canonical fields. Present it on POST /v1/orders. confirm_expires_at_ns: type: integer format: int64 scope: $ref: '#/components/schemas/ScopeUsage' ScopeUsage: type: object properties: day_utc: type: string daily_notional_used_uusdc: type: integer format: int64 daily_notional_cap_uusdc: type: integer format: int64 description: 0 = no cap. daily_notional_remaining_uusdc: type: integer format: int64 daily_orders: type: integer format: int64 open_orders: type: integer description: The account's resting orders at preview time; -1 when the engine snapshot was unavailable. open_orders_cap: type: integer max_order_notional_uusdc: type: integer format: int64 approval_mode: type: string enum: - auto - require_human instrument_allowlist: type: array items: type: integer format: int64 PendingOrder: type: object required: - pending_id - status - instrument_id - side - action - order_type - count - notional_uusdc - created_at_ns - expires_at_ns - credential_id properties: pending_id: type: integer format: int64 status: type: string enum: - pending_approval state: type: string enum: - pending - approved - rejected description: Present on GET /v1/orders/pending rows. instrument_id: type: integer format: int64 client_order_id: type: string side: $ref: '#/components/schemas/OrderSide' action: $ref: '#/components/schemas/OrderAction' order_type: $ref: '#/components/schemas/OrderType' price_pips: type: integer format: int32 count: type: integer notional_uusdc: type: integer format: int64 description: The scope's notional for the order (see POST /v1/credentials). created_at_ns: type: integer format: int64 expires_at_ns: type: integer format: int64 description: Undecided past this instant, the row lapses (15 minutes). credential_id: type: integer format: int64 description: The agent credential that parked it. agent: type: string description: The agent descriptor's `name`, when set. PendingDecision: type: object required: - pending_id - decision - decided_at_ns properties: pending_id: type: integer format: int64 decision: type: string enum: - approved - rejected decided_at_ns: type: integer format: int64 order: $ref: '#/components/schemas/PlaceOrderResponse' reject_reason: type: string description: On approval, the engine's reject reason when it refused the submitted order (the row stays `approved`). PreviewBook: type: object properties: best_bid_pips: type: - integer - 'null' best_ask_pips: type: - integer - 'null' mid_pips: type: - integer - 'null' spread_pips: type: - integer - 'null' mark_pips: type: - integer - 'null' description: Margined listings with a mark; null otherwise. PreviewExecution: type: object required: - crossing_count - resting_count - est_fill_pips - est_fill_notional_uusdc - slippage_pips_vs_mid - cost_vs_mid_uusdc - max_cost_binding properties: crossing_count: type: integer description: Contracts that would match now against resting liquidity. resting_count: type: integer description: Contracts that would rest (0 for market orders). est_fill_pips: type: - integer - 'null' description: VWAP of the crossing part; null if nothing crosses. est_fill_notional_uusdc: type: integer format: int64 slippage_pips_vs_mid: type: integer description: Positive = paid through mid. cost_vs_mid_uusdc: type: integer format: int64 max_cost_binding: type: boolean description: Market BUY only — max_cost stopped the walk short of count. PreviewFees: type: object required: - maker_fee_rate_bps - taker_fee_rate_bps - est_taker_fee_uusdc - est_maker_fee_uusdc - est_total_cost_uusdc - breakeven_pips properties: maker_fee_rate_bps: type: integer taker_fee_rate_bps: type: integer est_taker_fee_uusdc: type: integer format: int64 description: On the crossing part (venue-favorable ceil + flat per contract). est_maker_fee_uusdc: type: integer format: int64 description: If the resting part later fills as maker. est_total_cost_uusdc: type: integer format: int64 description: taker + maker + cost through mid. breakeven_pips: type: integer description: Adverse move per contract that recovers est_total_cost (ceil). PreviewMargin: type: object required: - sub_account_id - margin_cash_uusdc - equity - im_held_now - im_instrument_now - im_instrument_after - im_delta - im_held_after - free_collateral_after - utilization_after_bps - position_now - position_if_filled - im_bps properties: sub_account_id: type: integer margin_cash_uusdc: type: integer format: int64 equity: type: integer format: int64 im_held_now: type: integer format: int64 description: The account's total IM hold in the snapshot. im_instrument_now: type: integer format: int64 description: Netted hold on this instrument now (spec §5.4). im_instrument_after: type: integer format: int64 description: Netted hold on this instrument with this order resting (zero delta for reduce_only). im_delta: type: integer format: int64 im_held_after: type: integer format: int64 free_collateral_after: type: integer format: int64 description: equity − im_held_after. utilization_after_bps: type: integer format: int64 description: im_held_after / equity in bps; 0 when equity ≤ 0. position_now: type: integer format: int64 position_if_filled: type: integer format: int64 im_bps: type: integer description: Effective IM bps (expiry ramp applied). PlaceOrderRequest: type: object required: - instrument_id - side - action - order_type - count properties: instrument_id: type: integer format: int64 sub_account_id: type: integer format: int32 default: 0 client_order_id: type: string maxLength: 64 description: Optional client-supplied idempotency key. A retry with the same key (within the ~15-minute Edge dedup window) replays the ORIGINAL ack instead of re-placing; the same key with a DIFFERENT order body is rejected 409 `client_order_id_reuse`. After an engine-ack timeout the outcome is unknown and a same-key retry gets 409 `order_outcome_unknown` — query GET /v1/orders before retrying under a new key. The window clears on an Edge restart (documented at-most-once semantics; the engine itself never double-fills a sequenced order). side: $ref: '#/components/schemas/OrderSide' action: $ref: '#/components/schemas/OrderAction' order_type: $ref: '#/components/schemas/OrderType' tif: $ref: '#/components/schemas/TimeInForce' price_pips: type: integer format: int32 minimum: 1 maximum: 9999 description: Required for `order_type=limit`. Integer pips (1–9999 = 0.0001–0.9999). count: type: integer format: int32 minimum: 1 description: Number of contracts. max_cost: type: integer format: int64 description: 'Required for `order_type=market` + `action=buy`. Forbidden for `order_type=market` + `action=sell`. Atomic units of the settlement asset (USDC has 6 decimals). ' stp_qualifier: $ref: '#/components/schemas/STPQualifier' reduce_only: type: boolean default: false description: 'RC-3 (B4): admit only if the order strictly reduces the position; fill-time auto-cancel. Margin-era.' post_only: type: boolean default: false description: 'RC-3 (B4): reject if the order would cross (take) on entry. Margin-era.' confirm_token: type: string description: 'Optional (0.12.0): the token from `POST /v1/orders/stage`. Single-use, 60 s, bound to this order''s canonical fields (everything except `client_order_id` and the token itself). If presented it must redeem, else `409 confirm_token_invalid`.' PlaceOrderResponse: type: object required: - order_id - correlation_id - status - filled_count - resting_count - side - action - order_type - count - edge_received_at_ns - sequencer_committed_at_ns - engine_applied_at_ns properties: order_id: type: integer format: int64 sequencer_correlation_id: type: integer format: int64 description: Sequencer-assigned correlation for this submission (distinct from the envelope's HTTP `correlation_id`). client_order_id: type: string description: Echo of the request's idempotency key, when one was supplied. status: $ref: '#/components/schemas/OrderStatus' filled_count: type: integer format: int32 resting_count: type: integer format: int32 reject_reason: $ref: '#/components/schemas/OrderRejectReason' side: $ref: '#/components/schemas/OrderSide' action: $ref: '#/components/schemas/OrderAction' order_type: $ref: '#/components/schemas/OrderType' price_pips: type: integer format: int32 count: type: integer format: int32 edge_received_at_ns: type: integer format: int64 description: (V0.1 T1-5) PTP Unix ns at which Edge first read this order off the wire (post-TLS, pre-routing). Subtract from `sequencer_committed_at_ns` for the network+Edge+commit span. Spec §19.0.1. sequencer_committed_at_ns: type: integer format: int64 description: '(V0.1 T1-5) Unix ns at which the sequencer assigned this order its global sequence number and committed it to the cluster log. NOTE: sourced from the Aeron Cluster commit time, which is Unix MILLISECONDS, normalised to ns by ×1e6 — so this value carries millisecond precision (the same underlying clock as the documented `Fill.ts_ns` artifact), unlike the nanosecond-precise edge_received_at_ns / engine_applied_at_ns.' engine_applied_at_ns: type: integer format: int64 description: (V0.1 T1-5) PTP Unix ns at which the matching engine applied this order and produced the outcome. `engine_applied_at_ns − sequencer_committed_at_ns` is the dispatch+apply span. CancelOrderResponse: type: object required: - order_id - status - correlation_id properties: order_id: type: integer format: int64 status: type: string enum: - canceled sequencer_correlation_id: type: integer format: int64 OpenOrder: type: object required: - order_id - instrument_id - sub_account_id - api_side - action - order_type - tif - price_pips - quantity properties: order_id: type: integer format: int64 instrument_id: type: integer format: int64 sub_account_id: type: integer format: int32 api_side: $ref: '#/components/schemas/OrderSide' action: $ref: '#/components/schemas/OrderAction' order_type: $ref: '#/components/schemas/OrderType' tif: $ref: '#/components/schemas/TimeInForce' price_pips: type: integer format: int32 quantity: type: integer format: int32 Balance: type: object required: - asset_id - total - held - available properties: asset_id: type: integer format: int32 description: V0 only `1` (USDC). total: type: integer format: int64 description: total = available + held (atomic units). held: type: integer format: int64 description: Locked by open orders + pending withdrawals. available: type: integer format: int64 Position: type: object description: 'API-5 signed-qty migration. `signed_qty` is the shared field. Margined positions add `last_settlement_price` (engine state, the SV-2 basis) and omit the legacy yes/no. Event contracts DUAL-SERVE `yes_position` / `no_position` alongside the YES-collapsed `signed_qty` for one client release cycle. ' required: - instrument_id - sub_account_id - signed_qty properties: instrument_id: type: integer format: int64 sub_account_id: type: integer signed_qty: type: integer format: int64 last_settlement_price: type: integer format: int64 yes_position: type: integer format: int64 no_position: type: integer format: int64 Fill: type: object required: - event_seq - ts_ns - instrument_id - maker_order_id - taker_order_id - your_side - your_action - price_pips - count - correlation_id properties: event_seq: type: integer format: int64 description: Cluster sequence number for this fill — monotonic, ordered, deduplication key. ts_ns: type: integer format: int64 description: Aeron Cluster timestamp at sequence (caveat - milliseconds, not nanoseconds — schema-name historical artefact). instrument_id: type: integer format: int64 maker_order_id: type: integer format: int64 taker_order_id: type: integer format: int64 your_side: type: string enum: - maker - taker description: Which side of the trade you were on. your_action: type: string enum: - buy - sell description: Your action from your perspective (after YES/NO normalisation). price_pips: type: integer format: int32 count: type: integer format: int32 sequencer_correlation_id: type: integer format: int64 fee_uusdc: type: integer format: int64 description: 'Your OWN leg fee for this fill, signed µUSDC (+charge / −rebate) — parity with the WS `fill` frame (0.11.0). Zero on rows indexed before the fee columns existed.' tag: type: string enum: - normal - liquidation - adl description: Fill tag (§14.3) — parity with the WS `fill` frame (0.11.0). credential_id: type: integer format: int64 description: Attribution (0.14.0) — the credential that placed YOUR order in this fill. Absent for orders placed before 0.14.0. agent: type: string description: Attribution (0.14.0) — the placing credential's agent descriptor `name`, when set. FillsPage: type: object required: - fills - next_cursor properties: fills: type: array items: $ref: '#/components/schemas/Fill' next_cursor: type: - string - 'null' description: Pass as `cursor` for the next (older) page; null on the last page. Snapshot: type: object description: Atomic account snapshot at engine_seq_applied. Event-contract positions dual-serve yes/no; margined sub-accounts add the margin block. required: - engine_seq_applied - balances - positions - open_orders - pending_withdrawals properties: engine_seq_applied: type: integer format: int64 balances: type: array items: type: object required: - asset_id - total - held properties: asset_id: type: integer format: int64 total: type: integer format: int64 held: type: integer format: int64 positions: type: array items: $ref: '#/components/schemas/Position' open_orders: type: array items: type: object required: - order_id - instrument_id - side - action - price_pips - count - filled_count properties: order_id: type: integer format: int64 instrument_id: type: integer format: int64 side: type: string enum: - 'yes' - 'no' action: type: string enum: - buy - sell price_pips: type: integer count: type: integer format: int64 description: Remaining (un-filled) contract count of the resting order. filled_count: type: integer format: int64 description: Always 0 in V0.1 — the atomic engine snapshot does not carry partial-fill history. Use GET /v1/orders/{order_id} or GET /v1/fills for fills. pending_withdrawals: type: array items: type: object required: - withdrawal_id - asset_id - amount - state properties: withdrawal_id: type: integer format: int64 asset_id: type: integer format: int64 amount: type: integer format: int64 state: type: string enum: - pending description: 'Engine view. A withdrawal listed here has an active hold the engine has not yet seen finalized, so V0.1 always reports "pending". The full Custody lifecycle (the canonical WithdrawalState schema: pending_finality / broadcast / finalized / failed) is available via GET /v1/withdrawals/{id} — that''s the authoritative per-withdrawal view, separate from this engine-snapshot field.' margin: $ref: '#/components/schemas/MarginBlock' description: Present for margined sub-accounts; omitted for the fully-collateralized event-contract product. MarginBlock: type: object description: Per-sub-account margin block. All µUSDC int64. Derived but served at engine_seq_applied. required: - sub_account_id - equity - im_held - mm_required - free_collateral - margin_withdrawable - reserved_funding - positions properties: sub_account_id: type: integer equity: type: integer format: int64 im_held: type: integer format: int64 mm_required: type: integer format: int64 free_collateral: type: integer format: int64 margin_withdrawable: type: integer format: int64 reserved_funding: type: integer format: int64 positions: type: array items: type: object required: - instrument_id - qty - last_settlement_price - upnl_at_mark - mark_seq properties: instrument_id: type: integer format: int64 qty: type: integer format: int64 last_settlement_price: type: integer format: int64 upnl_at_mark: type: integer format: int64 mark_seq: type: integer format: int64 funding_net_24h_uusdc: type: integer format: int64 description: 0.15.0 — the account's net funding on this instrument over the last 24 h (signed). Absent when the audit store is unavailable or holds no payments yet. funding_last_uusdc: type: integer format: int64 description: 0.15.0 — the latest funding payment on this instrument (signed, negative = paid). Absent as above. FundingPayment: type: object required: - event_seq - boundary_ns - instrument_id - sub_account_id - rate_fp8 - position_qty - mark_ticks - notional_uusdc - payment_uusdc - dollar_capped properties: event_seq: type: integer format: int64 boundary_ns: type: integer format: int64 description: The funding boundary instant. instrument_id: type: integer format: int64 sub_account_id: type: integer description: 1 (the margin sub-account) in V0. rate_fp8: type: integer format: int64 description: The boundary's settled rate (1e-8 per interval, post-caps). position_qty: type: integer format: int64 description: Signed snapshot position at the boundary (contracts). mark_ticks: type: integer format: int32 description: The boundary mark the notional used (signed ticks). notional_uusdc: type: integer format: int64 description: max(|mark|, floor) × |position_qty| × multiplier — the payment base. payment_uusdc: type: integer format: int64 description: Signed cash delta to the account — negative = paid (ceil), positive = received (floor). dollar_capped: type: boolean description: True when the dollar cap clipped this leg. FundingPaymentsPage: type: object required: - payments - next_cursor - totals properties: payments: type: array items: $ref: '#/components/schemas/FundingPayment' next_cursor: type: - string - 'null' description: Pass as `cursor` for the next (older) page; null on the last page. totals: type: object required: - paid_uusdc - received_uusdc - net_uusdc - boundaries properties: paid_uusdc: type: integer format: int64 description: Magnitude of the page's negative legs. received_uusdc: type: integer format: int64 net_uusdc: type: integer format: int64 boundaries: type: integer description: Distinct boundaries on the page. FundingSummary: type: object required: - engine_seq_applied - next_boundary_ns - instruments - net_uusdc_24h - predicted_next_uusdc - estimate_note properties: engine_seq_applied: type: integer format: int64 next_boundary_ns: type: integer format: int64 description: The next instant on the venue's funding grid. net_uusdc_24h: type: integer format: int64 description: Sum over instruments. predicted_next_uusdc: type: integer format: int64 description: Sum of the per-instrument estimates. estimate_note: type: string instruments: type: array items: $ref: '#/components/schemas/FundingSummaryInstrument' FundingSummaryInstrument: type: object required: - instrument_id - net_uusdc_24h - net_uusdc_7d - net_uusdc_all - boundaries - position_qty_now - mark_uusdc - next_boundary_ns properties: instrument_id: type: integer format: int64 net_uusdc_24h: type: integer format: int64 net_uusdc_7d: type: integer format: int64 net_uusdc_all: type: integer format: int64 description: Since the venue began recording payments for this account. boundaries: type: integer format: int64 description: Boundaries with a payment on record. last_payment_uusdc: type: - integer - 'null' format: int64 last_boundary_ns: type: - integer - 'null' format: int64 position_qty_now: type: integer format: int64 description: Signed current position (margin sub-account). mark_uusdc: type: integer format: int64 description: Current mark in µUSDC per contract unit (signed). last_rate_fp8: type: - integer - 'null' format: int64 description: The instrument's last settled rate; null before its first boundary. predicted_next_uusdc: type: - integer - 'null' format: int64 description: ESTIMATE — last rate × |mark| × position, ledger sign (negative = would pay). Null without a position or a rate. next_boundary_ns: type: integer format: int64 InsuranceFund: type: object required: - engine_seq_applied - balance_uusdc - flows properties: engine_seq_applied: type: integer format: int64 balance_uusdc: type: integer format: int64 next_cursor: type: - string - 'null' flows: type: array items: type: object required: - event_seq - ts - amount_uusdc - cause - instrument - mark_seq properties: event_seq: type: integer format: int64 ts: type: integer format: int64 amount_uusdc: type: integer format: int64 description: signed; + is an inflow to the fund cause: type: string enum: - penalty - unwind_gain - funding_dust - operator_topup - shortfall_cover - dispersal instrument: type: integer format: int64 mark_seq: type: integer format: int64 LiquidationMetrics: type: object required: - delay_hours - cutoff_ns - buckets properties: delay_hours: type: integer cutoff_ns: type: integer format: int64 buckets: type: array items: type: object required: - instrument_id - hour_start_ns - liquidated_notional_uusdc - count properties: instrument_id: type: integer format: int64 hour_start_ns: type: integer format: int64 liquidated_notional_uusdc: type: integer format: int64 count: type: integer format: int64 ContractSpecResponse: type: object required: - engine_seq_applied - manifest_hash - spec properties: engine_seq_applied: type: integer format: int64 manifest_hash: type: string spec: $ref: '#/components/schemas/ContractSpec' ContractSpec: type: object required: - instrument_id - tick_size_uusdc - product_class - im_bps - mmr_bps - funding_is_fee_free properties: instrument_id: type: integer format: int64 product_class: type: integer tick_size_uusdc: type: integer format: int64 basis_ticks: type: integer format: int64 im_bps: type: integer mmr_bps: type: integer limit_band_buy_bps: type: integer limit_band_sell_bps: type: integer fee_model: type: integer maker_fee_rate_bps: type: integer format: int32 taker_fee_rate_bps: type: integer format: int32 funding_is_fee_free: type: boolean has_price_domain: type: boolean description: True when the signed price domain is configured (min 0 is a real bound when set). min_price_ticks: type: integer format: int32 description: Signed domain floor in ticks (real only under has_price_domain). max_price_ticks: type: integer format: int32 exposure_floor_uusdc: type: integer format: int64 description: Per-contract margin-exposure floor (0 = none; power_products_spec §4.2-2). funding_dollar_cap_daily_rate_bps: type: integer description: PERP-8 dollar-cap daily rate (0 = venue default 720). funding_dollar_cap_lookback_hours: type: integer description: PERP-8 rolling-low lookback (0 = venue default 24). contract_size: type: integer description: 'Units of `unit` one contract delivers (0.7.0). Every current listing is 1: one contract''s notional at price P is exactly P.' unit: type: string description: The physical unit one contract is denominated in, e.g. MWh, BTC (0.7.0). Recorded at listing; metadata, never on the engine wire. MarginTransferRequest: type: object required: - direction - amount_uusdc properties: account_id: type: integer format: int64 description: Optional. When present it MUST equal the authenticated account — the session is the sole authority on whose margin moves. direction: type: string enum: - in - out description: '`in` = spot balance → margin sub-account; `out` = margin → spot.' amount_uusdc: type: integer format: int64 minimum: 1 description: Micro-USDC (1e-6 USDC), the API's standard integer money encoding. transfer_id: type: integer format: uint64 description: Optional client-chosen identity/idempotency token; generated by Edge when omitted. MarginTransferResponse: type: object required: - transfer_id - account_id - direction - amount_uusdc - status - sequencer_correlation_id properties: transfer_id: type: integer format: uint64 account_id: type: integer format: int64 direction: type: string enum: - in - out amount_uusdc: type: integer format: int64 status: type: string enum: - accepted description: Always `accepted` — accepted FOR SEQUENCING; the engine verdict is asynchronous. sequencer_correlation_id: type: integer format: int64 description: Engine-side correlation id — join to WS push events. paths: /v1/deposits/addresses: get: operationId: getDepositAddress tags: - Custody summary: Get (or allocate) a deposit address for the authenticated account. description: 'Returns the on-chain deposit address for the (asset, chain) pair, allocating one from the hot-wallet pool if no address has been issued yet. The same address is returned on subsequent calls — it''s a stable per-(account, asset, chain) identifier. V0 supports `asset=1` (USDC) and `chain=99` (mock chain). V1+ adds `chain=101` (Solana mainnet). ' security: - BearerAuth: [] parameters: - name: asset in: query required: false schema: type: integer format: int32 default: 1 description: Asset ID. V0 = 1 (USDC). - name: chain in: query required: false schema: type: integer format: int32 default: 99 description: Chain ID. V0 = 99 (mock); V1+ = 101 (Solana mainnet). responses: '200': description: Deposit address. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/DepositAddress' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/withdrawals: post: operationId: createWithdrawal tags: - Custody summary: Initiate a withdrawal to an off-platform address. description: 'Submits a withdrawal request. The account is debited synchronously (the amount moves from `available` to `held`); the on-chain broadcast happens asynchronously through the custody coordinator and worker pipeline. Monitor the withdrawal''s state via `GET /v1/withdrawals/{withdrawal_id}` — `pending_finality → broadcast → finalized`. Requires the account to be in a withdraw-capable state (`active` or `trade_frozen`). ' security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateWithdrawalRequest' examples: usdc_withdrawal: value: asset_id: 1 amount: 100000000 address: 9wfRgFJjN5gKx2dHnQq8VtFXc8VtFXqJZb7uHgPvBdSP responses: '202': description: Withdrawal accepted. The on-chain broadcast is asynchronous. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Withdrawal' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': description: Account is not in a withdraw-capable state. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/withdrawals/{withdrawal_id}: parameters: - $ref: '#/components/parameters/PathWithdrawalID' get: operationId: getWithdrawal tags: - Custody summary: Get the status of a withdrawal. description: 'Returns the full withdrawal record. `state` progresses through `pending_finality → broadcast → finalized` — the only path in V0/V0.1, where the in-process MockChain always succeeds and finalizes instantly. The `failed` terminal state is defined but never reached until real Solana custody (V1.7). ' security: - BearerAuth: [] responses: '200': description: Withdrawal record. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Withdrawal' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '404': description: No such withdrawal — or it belongs to another account. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/accounts: post: operationId: createAccount tags: - Accounts summary: Register a new account. description: 'Creates an account and issues an initial API credential. The `plaintext_key` in `initial_credential` is returned exactly once and cannot be retrieved later — store it immediately. Subsequent credentials can be issued via `POST /v1/credentials`. No authentication is required for this endpoint. ' security: [] requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CreateAccountRequest' examples: minimal: summary: Anonymous account value: {} with_handle: summary: Account with handle value: handle: alice responses: '201': description: Account created. The response envelope's `data.initial_credential.plaintext_key` is the only place the key is ever returned in plaintext. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/CreateAccountResponse' examples: created: $ref: '#/components/examples/CreateAccountResponse' '400': $ref: '#/components/responses/BadRequest' '500': $ref: '#/components/responses/InternalError' /v1/accounts/me: get: operationId: getMe tags: - Accounts summary: Return the authenticated account. security: - BearerAuth: [] responses: '200': description: The account that owns the supplied API key. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Account' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/auth/signup: post: operationId: signup tags: - Auth summary: Email+password signup; mints a session credential. description: 'Creates an account with entitlement mask 7 (no APITrading), stores the password (argon2id), and mints a session credential. `session_token` is a standard `.` bearer, returned exactly once, expiring after 7 days. On faucet-enabled venues (dev/staging) the signup credit is sequenced asynchronously; `faucet_uusdc` echoes the amount and is omitted when the faucet is off. Rate limit: 10 signups / 5 minutes per client IP. No authentication is required for this endpoint. ' security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SignupRequest' examples: minimal: summary: Signup without a handle (defaults to the email local part) value: email: alice@example.com password: correct-horse-battery with_handle: summary: Signup with an explicit handle value: email: alice@example.com password: correct-horse-battery handle: alice responses: '200': description: Account created and session minted. `data.session_token` is the only place the session bearer is ever returned. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/SessionResponse' '400': $ref: '#/components/responses/BadRequest' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/auth/login: post: operationId: login tags: - Auth summary: Email+password login; mints a session credential. description: 'Verifies the password and mints a fresh 7-day session credential. Failed logins are uniformly `401 unauthorized` whether the email is unknown or the password wrong (equalized timing) — the endpoint is not an account-existence oracle. Rate limit: 10 attempts / 5 minutes per (client IP, email). No authentication is required for this endpoint. ' security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' examples: login: value: email: alice@example.com password: correct-horse-battery responses: '200': description: Session minted. `data.session_token` is the bearer; `faucet_uusdc` is never present on login. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/SessionResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/auth/logout: post: operationId: logout tags: - Auth summary: Revoke the current session credential. description: 'Revokes the session credential authenticating this request; takes effect immediately. Only session credentials may call logout — an API key gets `400 invalid_request` (revoke keys via `DELETE /v1/credentials/{credential_id}`). ' security: - BearerAuth: [] responses: '200': description: Session revoked. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/LogoutResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' /v1/auth/confirm: post: operationId: confirmEmail tags: - Auth summary: Consume an e-mail confirmation link. description: 'Marks the account e-mail verified. Single-use, 24 h expiry; a newer link supersedes older ones. `400 token_invalid` covers every failure (unknown / expired / used / wrong purpose) — the endpoint is not a token oracle. No session is minted. No authentication is required for this endpoint. ' security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TokenRequest' responses: '200': description: E-mail verified. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/ConfirmResponse' '400': $ref: '#/components/responses/BadRequest' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/auth/confirm/resend: post: operationId: resendConfirmation tags: - Auth summary: Re-send the e-mail confirmation link. description: 'Issues a fresh confirmation link (superseding older ones) and e-mails it to the account address. No-op (`delivery: not_needed`) when already verified. Rate limit: 10 / hour per account. ' responses: '200': description: Resend outcome. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/ResendResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/auth/password/forgot: post: operationId: forgotPassword tags: - Auth summary: Request a password-reset link. description: 'Always `202` — the response is identical whether the address exists or not (no account enumeration); when it does, a 30-minute single-use reset link is sent asynchronously. Rate limit: 10 / 15 minutes per client IP and per e-mail. No authentication is required for this endpoint. ' security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ForgotPasswordRequest' responses: '202': description: Accepted (uniform). content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/AcceptedResponse' '400': $ref: '#/components/responses/BadRequest' '429': $ref: '#/components/responses/RateLimited' /v1/auth/password/reset: post: operationId: resetPassword tags: - Auth summary: Consume a reset link and set a new password. description: 'Sets the password, revokes all existing sessions (API keys untouched), marks the e-mail verified, and mints a fresh 7-day session. Password is validated before the single-use token is consumed. No authentication is required for this endpoint. ' security: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ResetPasswordRequest' responses: '200': description: Password set; fresh session minted. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/SessionResponse' '400': $ref: '#/components/responses/BadRequest' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/auth/password/change: post: operationId: changePassword tags: - Auth summary: Change the password of the signed-in account. description: 'Requires the current password; revokes every other session on the account (the caller keeps theirs). Session credentials only. ' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChangePasswordRequest' responses: '200': description: Password changed. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/ChangePasswordResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' /v1/credentials: post: operationId: createCredential tags: - Credentials summary: Issue a new API credential for the authenticated account. description: 'Mints a new credential with optional `label` and `entitlement_mask`. The mask defaults to the calling credential''s mask if omitted. As with `POST /v1/accounts`, `plaintext_key` is returned exactly once. ' security: - BearerAuth: [] requestBody: required: false content: application/json: schema: $ref: '#/components/schemas/CreateCredentialRequest' examples: minimal: value: {} labelled_readonly: value: label: frontend-readonly entitlement_mask: 8 agent_key_24h: value: label: spike-scalper entitlement_mask: 9 expires_in_s: 86400 agent_scoped: summary: A scoped agent credential (0.14.0) value: label: spike-scalper entitlement_mask: 9 expires_in_s: 604800 instrument_allowlist: - 1011 - 1012 max_order_notional_uusdc: 25000000000 max_daily_notional_uusdc: 250000000000 max_open_orders: 20 approval_mode: require_human agent: name: spike-scalper model: claude-sonnet-5 operator: acme-power-desk responses: '201': description: Credential created. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Credential' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' get: operationId: listCredentials tags: - Credentials summary: List the authenticated account's credentials. description: Returns all non-revoked credentials for the account. `plaintext_key` is never returned by this endpoint. security: - BearerAuth: [] responses: '200': description: Array of credentials (without `plaintext_key`). content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/Credential' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' /v1/credentials/{credential_id}: parameters: - $ref: '#/components/parameters/PathCredentialID' delete: operationId: revokeCredential tags: - Credentials summary: Revoke a credential by ID. description: Revokes the named credential. The currently-authenticated credential may revoke itself; the revocation takes effect immediately. security: - BearerAuth: [] responses: '204': description: Credential revoked. '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '500': $ref: '#/components/responses/InternalError' /v1/deadman: post: operationId: setDeadman tags: - Orders summary: Arm, refresh, or disarm the cancel-on-silence switch (0.11.0). description: 'Arms a per-account timer; if not refreshed within `ttl_ms` the venue publishes an account-scope mass cancel and disarms (one-shot). `ttl_ms: 0` disarms. Evaluated at the edge — an edge restart disarms every switch; re-arm on reconnect. ' security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DeadmanRequest' examples: arm_30s: value: ttl_ms: 30000 disarm: value: ttl_ms: 0 responses: '200': description: Current switch state. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/DeadmanState' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' get: operationId: getDeadman tags: - Orders summary: Read the cancel-on-silence switch state (0.11.0). security: - BearerAuth: [] responses: '200': description: Current switch state (all zero when never armed). content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/DeadmanState' '401': $ref: '#/components/responses/Unauthorized' /v1/account/limits: get: operationId: getAccountLimits tags: - Accounts summary: The calling credential's write rate budget (0.11.0). description: 'Per-credential fixed-window limit on the order-write endpoints, remaining budget, and reset time — mirrored on write responses as X-RateLimit-* headers. `enabled: false` when the venue has not turned the limiter on. ' security: - BearerAuth: [] responses: '200': description: Write budget for the calling credential. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/AccountLimits' '401': $ref: '#/components/responses/Unauthorized' /v1/support/tickets: post: operationId: createSupportTicket tags: - Support summary: Open a support ticket (subject, message, image attachments). description: '`multipart/form-data`. `subject` (≤200 chars) and `message` (≤10,000 chars) are required; `images` may carry up to 4 PNG/JPEG/GIF/WebP files, ≤4 MB each and ≤10 MB in total (content-sniffed, not trusted from the filename). The ticket is stored before any delivery attempt; `delivery` is `sent` when the support inbox received the e-mail, `queued` when the venue has no mail relay configured or delivery failed (the ticket is kept either way). Rate-limited to 10/min per caller. ' security: - BearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object required: - subject - message properties: subject: type: string maxLength: 200 message: type: string maxLength: 10000 images: type: array maxItems: 4 items: type: string format: binary responses: '201': description: Ticket stored (and e-mailed when `delivery` is `sent`). content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object properties: data: type: object required: - ticket_id - delivery properties: ticket_id: type: integer format: int64 delivery: type: string enum: - sent - queued '400': description: Missing/oversized fields or a non-image attachment. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '413': description: Attachments exceed the size limits. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/instrument/instruments: get: operationId: listInstrumentsFull tags: - Instrument summary: List operator-defined instruments (read-only). description: Returns every instrument managed by the instrument service with full metadata (resolution criterion, closes_at, current state, resolved outcome if any). security: [] responses: '200': description: Array of instruments. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/Instrument' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instrument/instruments/{instrument_id}: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getInstrumentFull tags: - Instrument summary: Get a single instrument's full metadata. security: [] responses: '200': description: Instrument metadata. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Instrument' '400': $ref: '#/components/responses/BadRequest' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instrument/resolution/submit: post: operationId: submitResolution tags: - Instrument summary: Submit a resolution outcome for an instrument (reporter only). description: 'Reporters submit the binary outcome (YES/NO) for an instrument in the `pending` lifecycle state. V0 is operator-attested with a single reporter key; V1 introduces reporter quorum and a dispute window. Authentication is via the `X-Reporter-Key` header (distinct from customer Bearer tokens). ' security: - ReporterKey: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SubmitResolutionRequest' examples: yes_outcome: summary: YES outcome value: instrument_id: 1 outcome_pips: 10000 evidence_ref: https://reporter.example.com/proof/1 reporter_id: 42 no_outcome: summary: NO outcome value: instrument_id: 1 outcome_pips: 0 responses: '200': description: Resolution recorded; instrument advances to FINAL. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/SubmitResolutionResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instrument/resolution/preview/{instrument_id}: get: operationId: previewResolution tags: - Instrument summary: Preview the venue's last selected index value before confirming a b′ resolution (reporter only). description: 'Advisory operator-confirm aid for index-resolved (b′) binaries: returns the last journaled selected index value (the price component''s slot-value journal) and its staleness. The engine derives the authoritative b′ outcome from its own sequenced index state — this preview never re-derives it. ' security: - ReporterKey: [] parameters: - $ref: '#/components/parameters/PathInstrumentID' responses: '200': description: Instrument state plus the last selected index value, when one exists. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PreviewResolutionResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instrument/margin_metadata: get: operationId: listMarginMetadata tags: - Instrument summary: Margined-instrument metadata registry — identity/display records. description: 'Public identity/display record for every listed margined instrument, recorded at listing time. base/quote/expiry_date derive from the listing''s price_feed_id; symbol/display_name are operator-overridable derivations and symbols are unique venue-wide. Join against GET /v1/contract_specs (economics) and GET /v1/instruments (trading state). ' responses: '200': description: Every margined instrument's metadata record. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: object required: - metadata properties: metadata: type: array items: $ref: '#/components/schemas/MarginMetadata' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments: get: operationId: listInstruments tags: - Market Data summary: List instruments known to the matching engine. description: Returns a lightweight snapshot of every instrument the engine currently has loaded with its lifecycle state. For the operator-authored metadata (resolution criterion, closes_at, handle), use `/v1/instrument/instruments`. security: [] responses: '200': description: Array of instrument snapshots. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/InstrumentSnapshot' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments/{instrument_id}: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getInstrument tags: - Market Data summary: Get an instrument snapshot. security: [] responses: '200': description: Engine snapshot of one instrument. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/InstrumentSnapshot' '400': $ref: '#/components/responses/BadRequest' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments/{instrument_id}/orderbook: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getOrderbook tags: - Market Data summary: Get the order book for an instrument. description: 'Returns the full top-of-book ladder for both the YES and NO sides. Prices are integer pips (1–9999); counts are aggregate order counts at that price (not contract quantity totals). ' security: [] responses: '200': description: Order book snapshot. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Orderbook' '400': $ref: '#/components/responses/BadRequest' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments/{instrument_id}/candles: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getCandles tags: - Candles summary: Get OHLCV candles for charting. description: 'Returns time-bucketed OHLCV bars. The `from`/`to` window is in Unix **seconds**; either `from` + `to` OR `countback` + `to` should be supplied. Bars include a `closed` boolean — `true` means the bar window has elapsed and the values are final; the latest in-flight bar omits `closed` and may update on the `candles` WebSocket channel. History depth (0.13.0): recent bars come from the edge''s in-memory window; older bars are served transparently from the durable candle store (retention: 1m 120 days, 5m 2 years, 15m/1h/1d indefinitely). At most 12,000 bars per call — page back by moving `to`. ' security: [] parameters: - name: resolution in: query required: true schema: type: string enum: - 1m - 5m - 15m - 1h - 1d description: Candle bar resolution. - name: from in: query required: false schema: type: integer format: int64 description: Window start (Unix seconds, inclusive). Mutually exclusive with `countback`. - name: to in: query required: false schema: type: integer format: int64 description: Window end (Unix seconds, default `now`). - name: countback in: query required: false schema: type: integer minimum: 1 description: Number of bars to return ending at `to`. Mutually exclusive with `from`. - name: side in: query required: false schema: type: string enum: - 'yes' - 'no' default: 'yes' description: Which side's prints to chart. responses: '200': description: Candle series. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/CandleSeries' '400': $ref: '#/components/responses/BadRequest' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/open_interest: get: operationId: getOpenInterest tags: - Market Data summary: Per-instrument open interest (margined listings). description: One-sided open interest for every margined listing, in contract units and mark-notional µUSDC, exact at one engine snapshot seq. Served from a ~2s single-flight cache; event-class (fully collateralized) instruments are not included. security: [] responses: '200': description: Open-interest rows for all margined instruments. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/OpenInterestSnapshot' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments/{instrument_id}/trades: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getInstrumentTrades tags: - Market Data summary: Public trade tape for an instrument — paginated. description: 'Returns a paginated, anonymised projection of the `fills` table for the given instrument. Used by tape-driven analyses (the MM bot''s Kalman fair-value filter, third-party tape consumers). No account identifiers appear in the response. ' parameters: - in: query name: limit schema: type: integer minimum: 1 maximum: 1000 default: 100 - in: query name: cursor description: Opaque cursor returned by a previous call's `next_cursor`. schema: type: string - in: query name: since_event_seq description: Inclusive lower bound on `event_seq`. Mutually exclusive with `cursor`. schema: type: integer format: int64 responses: '200': description: Paginated trade tape. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: object required: - trades properties: trades: type: array items: type: object required: - event_seq - ts_ns - instrument_id - price_pips - count - taker_side properties: event_seq: type: integer format: int64 ts_ns: type: integer format: int64 instrument_id: type: integer format: int64 price_pips: type: integer minimum: 1 maximum: 9999 count: type: integer format: int64 taker_side: type: string enum: - buy - sell description: Aggressor action under YES-collapsed convention. next_cursor: type: - string - 'null' description: Pass back as `cursor` to retrieve the next page; null when no more pages. '400': $ref: '#/components/responses/BadRequest' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/instruments/{instrument_id}/funding: parameters: - $ref: '#/components/parameters/PathInstrumentID' get: operationId: getInstrumentFunding tags: - Market Data summary: Public funding-rate history for a perpetual (0.13.0). description: 'One record per funding boundary, newest first, cursor-paginated like the trade tape: the engine-computed rate (fixed-point 1e-8 per interval), its premium and interest components, and whether the boundary was a degenerate skip. Empty for instruments without funding. Cached 10 s; 120 requests / minute per client IP. ' security: [] parameters: - in: query name: limit schema: type: integer minimum: 1 maximum: 1000 default: 100 - in: query name: cursor description: Opaque cursor returned by a previous call's `next_cursor`. schema: type: string - in: query name: since_event_seq description: Inclusive lower bound on `event_seq`. Mutually exclusive with `cursor`. schema: type: integer format: int64 responses: '200': description: Paginated funding-rate history. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/FundingPage' '400': $ref: '#/components/responses/BadRequest' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/fees: get: operationId: getFees tags: - Market Data summary: Public fee schedule per margined listing (0.11.0). description: 'Signed maker/taker rates (bps of notional; negative = rebate), flat per-contract fees, and the funding/delivery fee flags, per margined instrument. Keyless. Same values as the contract-spec manifest fee block. Cached 10 s; 120 requests / minute per client IP. ' security: [] responses: '200': description: Fee schedule. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/FeeSchedule' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/ServiceUnavailable' /healthz: get: operationId: healthz tags: - Operations summary: Liveness probe. description: Always returns 200 OK once the process has started, even before the API listener is bound. Served on the health port (8080 in dev). security: [] servers: - url: http://127.0.0.1:18101 description: Local development health port. responses: '200': description: Service is alive. content: text/plain: schema: type: string examples: - OK /readyz: get: operationId: readyz tags: - Operations summary: Readiness probe. description: Returns 200 OK only after the API listener is bound and accepting connections. Served on the health port. security: [] servers: - url: http://127.0.0.1:18101 description: Local development health port. responses: '200': description: Service is ready to accept traffic. '503': description: Service is up but not yet ready. /metrics: get: operationId: metrics tags: - Operations summary: Prometheus exposition. description: Scrape target for Prometheus. Served on the health port. Mostly Go-runtime metrics in V0; service-specific counters will be added in V1. security: [] servers: - url: http://127.0.0.1:18101 description: Local development health port. responses: '200': description: Prometheus exposition format. content: text/plain: schema: type: string /healthz/venue: get: operationId: getVenueHealth tags: - Operations summary: Venue-functional liveness probe (public). description: 'Judges functional venue health: two-sided books, fill-tape freshness, and disk headroom. `status` is `ok` only when every check passes; failing checks are named in `reasons`. Served on the main API port (unlike `/healthz`/`/readyz`/`/metrics`, which live on the operations health port) so external uptime monitors can probe it. ' security: [] responses: '200': description: Health verdict — HTTP 200 for BOTH healthy and unhealthy; monitors must match on `data.status`, not the status code. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/VenueHealthResponse' examples: healthy: summary: All checks green value: data: status: ok books_two_sided: 6 last_fill_age_s: 0 disk_used_pct: 34 correlation_id: f1e870f6-363e-457e-955a-e65dcef1f590 unhealthy: summary: Stale tape value: data: status: unhealthy reasons: - tape_stale books_two_sided: 6 last_fill_age_s: 40025 disk_used_pct: 31 correlation_id: 3897721d-941f-4712-9352-625de34abd54 /v1/status: get: operationId: getServiceStatus tags: - Operations summary: Per-service health (public). description: 'Probes each venue service and reports `ok` | `down` per service with the probe latency. `status` is `ok` when everything answers, `degraded` when a non-core service (e.g. the audit store) is down, `down` when a core service (edge, trading engine, instrument registry) is. HTTP 200 for every verdict — match on `data.status`. Cached 5 s; rate-limited. ' security: [] responses: '200': description: Status report. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object properties: data: $ref: '#/components/schemas/ServiceStatusReport' /v1/power/ercot/prices: get: operationId: getErcotPrices tags: - Power summary: Latest ERCOT hub and load-zone prices (public). description: 'For each of ERCOT''s 15 hub and load-zone settlement points: the latest 5-minute SCED LMP, the latest 15-minute real-time settlement point price (the RT perps'' settlement basis), and the RT perpetual listed on the point. Reference data collected from ERCOT''s public display reports — not an index input. A price is `null` until first observed and `stale` when flagged invalid upstream or older than 20 min (LMP) / 40 min (SPP). Values are µUSDC per MWh and may be negative. Cached 10 s. Rate limit: 120 requests / minute per client IP. No authentication is required for this endpoint. ' security: [] responses: '200': description: Latest prices for all 15 points. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PowerPrices' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/orders: post: operationId: placeOrder tags: - Orders summary: Place an order. description: "Places a limit or market order on the YES or NO side of a prediction-market instrument.\n\ \n- `order_type=limit` requires `price_pips` (1–9999).\n- `order_type=market` with `action=buy`\ \ requires `max_cost` (atomic units of the\n settlement asset, e.g. USDC atomic).\n- `order_type=market`\ \ with `action=sell` must NOT set `max_cost`.\n\nSettlement asset is fixed to USDC in V0 (`asset_id=1`).\n\ \nThe synchronous response carries the engine's outcome: fully filled, rested on the book,\nIOC-cancelled\ \ with no rest, or rejected. Resting orders subsequently match other\nincoming orders; subscribe\ \ to the `fill` WSS channel to receive fills in real time.\n" security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PlaceOrderRequest' examples: limit_buy_yes: summary: Limit BUY YES @ 0.55 value: instrument_id: 1 side: 'yes' action: buy order_type: limit tif: gtc price_pips: 5500 count: 100 market_buy_yes: summary: Market BUY YES with USDC cap value: instrument_id: 1 side: 'yes' action: buy order_type: market max_cost: 50000000 count: 100 fok_sell_no: summary: FOK SELL NO @ 0.40 value: instrument_id: 1 side: 'no' action: sell order_type: limit tif: fok price_pips: 4000 count: 50 responses: '200': description: 'Order processed by the engine. The `status` field describes the outcome: `accepted_fully_filled`, `accepted_rested`, `accepted_ioc_canceled`, or `rejected`. A `rejected` outcome is still returned as HTTP 200 when accompanied by a wire reject reason — see §`reject_reason` for the inferred HTTP status mapping when the reject promotes to 400/403/409/422 at the boundary. ' content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PlaceOrderResponse' examples: rested: $ref: '#/components/examples/PlaceOrderRested' fully_filled: $ref: '#/components/examples/PlaceOrderFullyFilled' '202': description: 'Parked for human approval (0.14.0): the calling credential has `approval_mode: require_human`. Nothing rests; see GET /v1/orders/pending.' content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PendingOrder' '400': description: Validation failed or wire-reject promoted to client error. Common error codes — `invalid_request`, `invalid_json`, `invalid_price`, `invalid_quantity`, `invalid_max_cost`, `unknown_instrument`, `invalid_api_fields`. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': description: 'Account is not in a tradable state. Error codes — `account_not_active`, `account_trade_frozen`. ' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: 'The instrument does not exist on the venue. Error code — `instrument_not_found` (until 2026-09-02 this case surfaced as `instrument_halted`/409).' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '409': description: 'Instrument lifecycle or self-trade prevention blocked the order. Error codes — `instrument_halted`, `stp_aborted`. Also the idempotency conflicts (audit F2): `client_order_id_reuse` (same key, different body) and `order_outcome_unknown` (same key while the original is in flight or timed out — query GET /v1/orders first). And (0.12.0) `confirm_token_invalid` — a presented `confirm_token` is unknown, expired, already used, or bound to a different order; re-stage.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '422': description: 'Reject reasons that map to "we understood the request but cannot execute it against the current book/balance". Error codes — `insufficient_funds`, `fok_would_not_fully_fill`, `max_cost_blocks_any_fill`, `market_no_liquidity`. ' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '504': description: Engine did not acknowledge the order within the deadline (default 2 s). Treat as unknown — the order may or may not have been sequenced. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' get: operationId: listOpenOrders tags: - Orders summary: List the authenticated account's open (resting) orders. description: Returns every order currently resting on a book that belongs to the calling account, across all instruments. security: - BearerAuth: [] responses: '200': description: Array of open orders. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/OpenOrder' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/orders/pending: get: operationId: listPendingOrders tags: - Orders summary: List orders parked for human approval (0.14.0). description: Undecided, unexpired orders parked by the account's `require_human` credentials, newest first. security: - BearerAuth: [] responses: '200': description: Pending orders. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/PendingOrder' '401': $ref: '#/components/responses/Unauthorized' /v1/orders/pending/{pending_id}/approve: post: operationId: approvePendingOrder tags: - Orders summary: Approve a parked order — submits it to the engine (0.14.0). description: 'Claims the pending row, submits the stored order on the account (attributed to the agent''s credential) and returns the decision with the engine outcome. The deciding credential must have `approval_mode: auto`.' security: - BearerAuth: [] parameters: - name: pending_id in: path required: true schema: type: integer format: int64 responses: '200': description: Decision recorded; `order` carries the engine outcome (which may itself be `rejected`). content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PendingDecision' '401': $ref: '#/components/responses/Unauthorized' '403': description: '`approver_not_allowed` — the deciding credential is itself `require_human`; or the account / entitlement rules of POST /v1/orders.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': $ref: '#/components/responses/NotFound' '409': description: '`pending_already_decided` or `pending_expired`.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/orders/pending/{pending_id}/reject: post: operationId: rejectPendingOrder tags: - Orders summary: Reject a parked order (0.14.0). description: Records the decision; nothing is submitted. Same authorisation and conflict rules as approve. security: - BearerAuth: [] parameters: - name: pending_id in: path required: true schema: type: integer format: int64 responses: '200': description: Decision recorded. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/PendingDecision' '401': $ref: '#/components/responses/Unauthorized' '403': description: '`approver_not_allowed`, or the account / entitlement rules of POST /v1/orders.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': $ref: '#/components/responses/NotFound' '409': description: '`pending_already_decided` or `pending_expired`.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/orders/stage: post: operationId: stageOrder tags: - Orders summary: Pre-trade preview + confirm token (0.12.0). Nothing is published. description: 'Same body as POST /v1/orders. Returns, from one engine snapshot, the book, the execution walk (crossing vs resting, VWAP, slippage vs mid), fee estimates and breakeven, the netted initial-margin hold before/after per spec §5.4 (margined listings), a best-effort `would_reject` mirror of admission, warnings, and a single-use 60-s `confirm_token` bound to the order. The engine stays authoritative. ' security: - BearerAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/PlaceOrderRequest' responses: '200': description: The preview. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/OrderPreview' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/orders/{order_id}: parameters: - $ref: '#/components/parameters/PathOrderID' get: operationId: getOrderByID tags: - Orders summary: Look up an order by ID — including terminal state. description: 'Returns the order''s full lifecycle state regardless of whether it is still resting, has been filled, cancelled, rejected, or partially filled. The order must belong to the calling account; foreign accounts return 403. Terminal orders are served from the Audit Indexer (ClickHouse `orders` table); resting orders are served from the Trading Engine''s live view. ' security: - BearerAuth: [] responses: '200': description: Order found; full lifecycle state returned. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: object required: - order_id - status - instrument_id - side - action - order_type - price_pips - count - filled_count - resting_count properties: order_id: type: integer format: int64 status: type: string enum: - resting - partially_filled - filled - canceled - rejected instrument_id: type: integer format: int64 side: type: string enum: - 'yes' - 'no' action: type: string enum: - buy - sell order_type: type: string enum: - limit - market price_pips: type: integer minimum: 1 maximum: 9999 count: type: integer format: int64 filled_count: type: integer format: int64 resting_count: type: integer format: int64 first_seen_at_ns: type: integer format: int64 terminal_at_ns: type: - integer - 'null' format: int64 reject_reason: type: - string - 'null' sequencer_correlation_id: type: integer format: int64 '401': $ref: '#/components/responses/Unauthorized' '403': description: Order belongs to a different account. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Order ID not known to either the engine or the audit indexer. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': $ref: '#/components/responses/ServiceUnavailable' delete: operationId: cancelOrder tags: - Orders summary: Cancel a resting order by ID. description: 'Cancels the named order. The order must belong to the calling account; cancelling someone else''s order returns 403. Idempotent — cancelling an already-cancelled or already-filled order returns 404. ' security: - BearerAuth: [] responses: '200': description: Cancellation processed. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/CancelOrderResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': description: 'Account state forbids cancellation, or the order belongs to another account. Error codes — `account_not_active`, `cancel_rejected` with reason `wrong_account`. ' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: Order not found (unknown ID, already cancelled, or already filled). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '504': description: Engine did not acknowledge within deadline. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' /v1/orders/cancel_all: post: operationId: cancelAll tags: - Orders summary: Cancel all of the calling account's resting orders on one instrument. description: "Cancels every resting order the calling account holds on a single\n`instrument_id`.\ \ **`instrument_id` is REQUIRED** — mass cancel is deliberately\nper-instrument; there is no all-instruments\ \ / account-wide kill form, and it does\n**not** enter a kill-switch state (spec §6.6).\n\nBacked\ \ by a single `MassCancel` SBE event. The sweep itself is **asynchronous**:\na deep book may take\ \ a while to drain, so this endpoint returns **202 Accepted**\nimmediately rather than blocking.\ \ The engine then, in one sequenced apply pass:\n\n - emits one `OrderCanceled` per affected\ \ order — each lands in the audit `orders`\n table (so `GET /v1/orders/{order_id}` reflects\ \ the cancellation) and drives the\n public `orderbook_delta` WS channel; then\n - emits a\ \ terminating `MassCancelComplete`, surfaced on the authenticated\n **`account`** WS channel\ \ as a `mass_cancel_complete` event carrying the\n authoritative `canceled_count`.\n\nCorrelate\ \ the 202 response with the WS completion event via the shared\n`correlation_id`. `estimated_count`\ \ is a best-effort hint taken from the live engine\nsnapshot at request time; the WS event carries\ \ the actual count.\n" security: - BearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: instrument_id: type: integer format: int64 description: The instrument whose resting orders (for this account) are cancelled. Omit or send 0 for ACCOUNT scope (0.11.0) — one sweep per listed instrument. responses: '202': description: Mass-cancel sequenced; per-order cancels + completion arrive via WS. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: object required: - status - instrument_id - correlation_id - estimated_count properties: status: type: string enum: - accepted description: Always "accepted" — the sweep runs asynchronously. instrument_id: type: integer format: int64 sequencer_correlation_id: type: integer format: int64 description: Join key for the mass_cancel_complete event on the account WS channel. estimated_count: type: integer format: int64 description: Best-effort count from the live snapshot; the WS completion event carries the authoritative canceled_count. scope: type: string enum: - instrument - account description: Which form ran (0.11.0). mass_cancels: type: array description: Account scope only — every per-instrument sweep published. items: type: object required: - instrument_id - sequencer_correlation_id - estimated_count properties: instrument_id: type: integer format: int64 sequencer_correlation_id: type: integer format: int64 estimated_count: type: integer format: int32 '400': description: Missing or invalid instrument_id. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': description: Account state forbids cancellation (requires an active account). content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/snapshot: get: operationId: getAccountSnapshot tags: - Account summary: Atomic per-account snapshot of balances + positions + open orders. description: 'Returns balances, positions, open orders, and pending withdrawals for the calling account — all guaranteed to reflect the same `engine_seq_applied`. Internally serves from the Trading Engine''s `SnapshotState(at_seq)` gRPC, filtered to the calling account. Eliminates the multi-poll race that separate calls to `/v1/balances`, `/v1/positions`, `/v1/orders` would otherwise produce. ' security: - BearerAuth: [] responses: '200': description: Atomic snapshot returned. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/Snapshot' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/balances: get: operationId: getBalances tags: - Market Data summary: Get the authenticated account's balances. description: 'Returns one row per asset. `total = available + held`. `held` is the portion locked against open orders or pending withdrawals. ' security: - BearerAuth: [] responses: '200': description: Array of balance rows. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/Balance' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/positions: get: operationId: getPositions tags: - Market Data summary: Get the authenticated account's positions. description: 'Returns one row per (instrument_id, sub_account_id). YES and NO positions are tracked separately; only one side will typically be non-zero for a given instrument. ' security: - BearerAuth: [] responses: '200': description: Array of position rows. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/Position' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/funding_payments: get: operationId: listFundingPayments tags: - Account summary: The caller's funding payments, newest first (0.15.0). description: One row per funding boundary per perpetual held, as the engine booked the leg — signed payment, snapshot position, boundary mark, notional, rate. Cursor-paginated; `totals` sums the page. security: - BearerAuth: [] parameters: - name: instrument_id in: query required: false schema: type: integer format: int64 - name: since_boundary_ns in: query required: false schema: type: integer format: int64 description: Inclusive lower bound on `boundary_ns`. - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 1000 default: 100 - name: cursor in: query required: false schema: type: string description: Opaque cursor from a previous response's `next_cursor`. responses: '200': description: Funding payments page. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/FundingPaymentsPage' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/funding_payments/summary: get: operationId: getFundingSummary tags: - Account summary: Per-instrument funding totals and the next-payment estimate (0.15.0). description: Net funding over 24 h / 7 d / all history per perpetual, the latest payment, the current position and mark, the last settled rate, and an explicitly-labelled estimate of the next payment. security: - BearerAuth: [] responses: '200': description: Funding summary. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/FundingSummary' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/fills: get: operationId: listFills tags: - Market Data summary: List the authenticated account's recent fills. description: 'Returns matched-trade rows from the audit indexer. Each fill has a `your_side` (`maker` or `taker`) and a `your_action` (`buy` or `sell`) field framed from the caller''s perspective. Note: this endpoint queries the ClickHouse projection, which lags real-time by ~100 ms (the audit indexer''s flush interval). For latency-sensitive fill notifications, subscribe to the `fill` WebSocket channel instead. ' security: - BearerAuth: [] parameters: - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 1000 default: 100 description: Maximum rows to return (newest first). - name: cursor in: query required: false schema: type: string description: Opaque pagination cursor from a prior response's `next_cursor` (audit F3; same idiom as /v1/insurance_fund flows and the trades tape). responses: '200': description: One page of fills, newest first. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/FillsPage' '401': $ref: '#/components/responses/Unauthorized' '503': $ref: '#/components/responses/ServiceUnavailable' /v1/margin_info: get: operationId: getMarginInfo tags: - Margin summary: Same-seq margin block projection. description: A read-only projection of the `margin` block alone; introduces zero engine state. security: - BearerAuth: [] responses: '200': description: Margin info content: application/json: schema: type: object required: - engine_seq_applied - margin properties: engine_seq_applied: type: integer format: int64 margin: $ref: '#/components/schemas/MarginBlock' /v1/insurance_fund: get: operationId: getInsuranceFund tags: - Market Data summary: Insurance-fund balance + itemized flows. description: '`balance_uusdc` is engine state (the venue INSURANCE account''s margin cash at `engine_seq_applied`). `flows` is the paginated itemized journal over exactly the six flow causes. Soak invariant: `balance == seeded + Σ(flows)`. Off-ledger recap claims are never a flow. ' parameters: - name: limit in: query schema: type: integer minimum: 1 maximum: 1000 default: 100 - name: cursor in: query schema: type: string responses: '200': description: Insurance fund content: application/json: schema: $ref: '#/components/schemas/InsuranceFund' /v1/liquidation_metrics: get: operationId: getLiquidationMetrics tags: - Market Data summary: T+24h delayed hourly liquidation aggregates. description: 'Per-instrument HOURLY `{liquidated_notional_uusdc, count}` aggregated from the liquidation fill tag, served on a T+24h delay — no bucket younger than 24h is ever returned (the real-time liquidation surface is deliberately deferred, §14.2.1). ' parameters: - name: instrument_id in: query schema: type: integer format: int64 responses: '200': description: Liquidation metrics content: application/json: schema: $ref: '#/components/schemas/LiquidationMetrics' /v1/contract_specs: get: operationId: listContractSpecs tags: - Market Data summary: List listed margined instruments with manifest hashes. responses: '200': description: Contract spec list content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: type: object required: - engine_seq_applied - instruments properties: engine_seq_applied: type: integer format: int64 instruments: type: array items: type: object required: - instrument_id - product_class - manifest_hash properties: instrument_id: type: integer format: int64 product_class: type: integer manifest_hash: type: string /v1/contract_specs/{instrument_id}: get: operationId: getContractSpec tags: - Market Data summary: Signed per-instrument manifest pinned by manifest_hash. description: '`manifest_hash` is the SHA-256 of the canonical `spec` bytes; a client re-marshals `spec` and re-hashes to verify byte-identity. Every snapshot/channel decode constant is resolvable from `spec`. A cryptographic signature over the hash is a planned addition. ' parameters: - name: instrument_id in: path required: true schema: type: integer format: int64 responses: '200': description: Contract spec content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/ContractSpecResponse' '404': $ref: '#/components/responses/NotFound' /v1/margin/transfer: post: operationId: marginTransfer tags: - Margin summary: Transfer cash between the spot balance and the margin sub-account. description: 'Moves settlement-asset cash between the account''s spot balance and its margin sub-account. `direction` is `in` (spot → margin) or `out` (margin → spot). Accepted for sequencing (202): the engine''s verdict is asynchronous and a rejected transfer applies nothing. Outbound transfers are bounded by the engine''s `margin_withdrawable` gate (`GET /v1/margin_info`). The authenticated account is the only account whose margin can move — a mismatched `account_id` in the body is rejected `forbidden`. ' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MarginTransferRequest' examples: fund_margin: summary: Fund margin with $1,000 value: direction: in amount_uusdc: 1000000000 responses: '202': description: Accepted for sequencing. `status` is always `accepted`; the engine's apply/reject verdict is asynchronous. content: application/json: schema: allOf: - $ref: '#/components/schemas/Envelope' - type: object required: - data properties: data: $ref: '#/components/schemas/MarginTransferResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': description: The body's `account_id` does not match the authenticated account, or the account's state forbids the action. '500': $ref: '#/components/responses/InternalError' /v1/ws: get: operationId: openWebSocket tags: - WebSocket summary: Open the WebSocket connection (HTTP/1.1 Upgrade). description: 'The Edge service speaks a small subscription-based protocol over WebSocket. The HTTP verb is `GET` with the standard `Upgrade: websocket` headers; after the upgrade, client and server exchange JSON frames. See `docs/exchange/api/services/websockets.md` for the protocol (subscribe/unsubscribe/ping operations) and the complete list of channels (`orderbook_delta`, `trade`, `candles`, `mark`, `market_lifecycle`, `fill`, `account`). Bearer authentication on the Upgrade request is optional but required for private channels (`fill`, `account`). Anonymous connections may subscribe to public channels only. This OpenAPI operation exists for codegen visibility; the wire-frame schemas are not modelled in OpenAPI itself (consider AsyncAPI for that). ' security: - {} - BearerAuth: [] parameters: - name: Upgrade in: header required: true schema: type: string enum: - websocket - name: Connection in: header required: true schema: type: string enum: - Upgrade - name: Sec-WebSocket-Key in: header required: true schema: type: string - name: Sec-WebSocket-Version in: header required: true schema: type: string enum: - '13' responses: '101': description: Protocol switched to WebSocket. From here, exchange JSON frames per the protocol in `docs/exchange/api/services/websockets.md`. x-websocket-channels: mark: scope: public gated_by: api.mark_channel_enabled description: API-2 public mark channel. Emits per mark update. payload: instrument_id: int64 mark: int64_ticks band_lo: int64_ticks band_hi: int64_ticks event_seq: int64 ts: int64 account: scope: private description: API-2 private account channel — carries the liquidation lifecycle and margin warnings for the authenticated account only. events: liquidation_started: canceled_order_count: int cured: bool event_seq: int64 liquidation_complete: filled_qty: int64 penalty: int64 shortfall_uusdc: int64 remainder_uusdc: int64 event_seq: int64 margin_warning: instrument: int64 equity_uusdc: int64 mm_requirement_uusdc: int64 mm_ratio_bps: int threshold_hit: int mark_event_seq: int64 settlement_applied: instrument_id: int64 vm_uusdc: int64 settle_ticks: int64 prev_settle_ticks: int64 event_seq: int64 fill: scope: private description: API-3 private fill channel. Carries the own-leg fee and the fill tag; liquidation fills are NOT on the public trade tape (§14.2.1). payload: fee_uusdc: int64 tag: normal|liquidation|adl