Documentation Index
Fetch the complete documentation index at: https://docs.openpx.trade/llms.txt
Use this file to discover all available pages before exploring further.
Coverage
| Exchange | Sourced | Synthetic | Omitted |
|---|---|---|---|
| kalshi | 9 | 2 | 0 |
| polymarket | 8 | 0 | 3 |
Synthetic — computed by OpenPX, not present upstream.
Omitted — upstream does not expose this concept.
Field crosswalk
| Unified field | Type | kalshi source | polymarket source | Transform | Notes |
|---|---|---|---|---|---|
id | string | Order.order_id (string), fallback CreateOrderV2Response.order_id | OpenOrder.id (string), fallback SendOrderResponse.orderID | direct | kalshi: Kalshi-issued order id. Stable across V1 GET responses and every V2 mutation response (Cancel, BatchCreate, BatchCancel all share the order_id field name). The fallback_ref pins V2 for drift detection — both call sites share the same string-typed field. polymarket: Order hash. GET endpoints expose it as id; POST /order response exposes it as orderID (note the casing). The adapter handles both via SDK-side aliasing. |
market_ticker | string | Order.ticker (string) | not exposed | direct | kalshi: V1 GET responses echo ticker. V2 mutation responses do NOT echo it; the adapter carries CreateOrderRequest.asset_id (which on Kalshi is the market ticker) into the response. Cancel paths synthesize an Order with an empty market_ticker — callers should fetch_order for full state. polymarket: Order.market_ticker is the unified market identifier; Polymarket’s per-outcome asset_id is a CTF token, not a market id. Both OpenOrder.market (on-chain condition ID) and SendOrderResponse (no market field) are wrong-shape for the unified meaning, and the create_order surface no longer accepts a slug — callers needing a slug must run fetch_market_lineage separately. Always empty on Polymarket. |
outcome | string | computed — Order.side ∈ {yes, no} → {"Yes", "No"}; V2 uses caller-frame | OpenOrder.outcome (string) | synthetic / direct | kalshi: V1 GET: re-canonicalize the side enum to title case. V2 mutation responses don’t echo outcome at all — the adapter carries the caller’s OrderOutcome::Yes/No through to the response. Kalshi markets are always binary; non-Yes/No outcome variants are rejected at request time with InvalidInput. polymarket: Free-form outcome label as published by Polymarket (typically "YES"/"NO" on binary markets, categorical labels on neg-risk markets). On create paths the adapter carries the caller-frame label since SendOrderResponse doesn’t echo it. |
side | OrderSide | computed — Order.action ∈ {buy, sell} → OrderSide enum | OpenOrder.side (string) | synthetic / direct | kalshi: V1 GET: action carries Buy/Sell while side carries the outcome (Yes/No) — the unified side is sourced from action, not from side. V2 mutation responses don’t echo action; the adapter preserves the caller-frame OrderSide. polymarket: BUY/SELL enum, 1:1 with unified OrderSide. |
price | number (double) | Order.yes_price_dollars (FixedPointDollars), fallback CreateOrderV2Response.average_fill_price | OpenOrder.price (string) | fixed_point_dollars / poly_price_to_f64 | kalshi: V1 GET returns both yes_price_dollars and no_price_dollars; the adapter reads the populated one and converts to the caller-frame outcome. V2 returns only average_fill_price (YES-frame, populated when fill_count \> 0); the adapter mirrors it for NO-side orders via the kalshi_v2_yes_frame_to_caller transform and falls back to the caller’s request price when no fill occurred. polymarket: OpenOrder.price is already a decimal probability string (e.g. "0.5"). On create paths the adapter carries the caller-frame price since SendOrderResponse doesn’t echo it. |
size | number (double) | Order.initial_count_fp (FixedPointCount), fallback CreateOrderV2Response.remaining_count | OpenOrder.original_size (string) | fixed_point_count / poly_decimal_to_f64 | kalshi: V1 GET reports initial_count_fp directly. V2 doesn’t include a single “size” field; the adapter reconstructs it as fill_count + remaining_count. The fallback_ref pins remaining_count for drift detection (its sibling fill_count is pinned via the filled field below). polymarket: Fixed-math 6-decimal string. On create paths the adapter carries the caller-frame size since SendOrderResponse doesn’t echo it. |
filled | number (double) | Order.fill_count_fp (FixedPointCount), fallback CreateOrderV2Response.fill_count | OpenOrder.size_matched (string) | fixed_point_count / poly_decimal_to_f64 | kalshi: V1 GET emits fill_count_fp (FixedPointCount). V2 emits a stripped fill_count (also FixedPointCount, same scaling). polymarket: Cumulative matched size on the read side. POST /order response path always sets this to 0.0 — taking_amount/making_amount on SendOrderResponse encode the executed quantity in different units and are not surfaced on the unified Order today. |
fee | number? (double) | CreateOrderV2Response.average_fee_paid (FixedPointDollars) | not exposed | fixed_point_dollars | kalshi: V2 reports per-contract average fee on the create response; the adapter multiplies by fill_count for the dollar total. V1 GET Order DOES expose taker_fees_dollars and maker_fees_dollars but parse_order doesn’t yet read them — fetch_order paths return fee: None. Future commit can add taker_fees_dollars + maker_fees_dollars to lift V1 fees too. polymarket: Polymarket charges fees at trade settlement, not on order creation or lookup. SendOrderResponse and OpenOrder don’t carry fee fields. Always None on the unified surface. |
status | OrderStatus | Order.status (OrderStatus) | OpenOrder.status (string), fallback SendOrderResponse.status | direct | kalshi: V1 GET: status is the Kalshi OrderStatus enum (resting | canceled | executed); the adapter maps to unified Open | Cancelled | Filled. V2 mutations don’t echo status; the adapter derives it from (fill_count, remaining_count) via kalshi_v2_status_from_counts (see vocabulary above). Cancel paths synthesize Cancelled directly. polymarket: OpenOrder uses prefixed ORDER_STATUS_* enum values; the SDK normalizes them to its own OrderStatusType (Live, Matched, Canceled, Delayed, Unmatched, …) before the adapter maps to unified OrderStatus. SendOrderResponse uses the unprefixed live | matched | delayed shape on the create response only. |
created_at | string (date-time) | Order.created_time (string (date-time)) | OpenOrder.created_at (integer) | parse_datetime / unix_seconds_to_utc | kalshi: V1 GET: RFC3339 string. V2 responses don’t include a creation timestamp; the adapter falls back to wall-clock at parse time. polymarket: Unix seconds. SendOrderResponse doesn’t echo created_at; on create paths the adapter falls back to wall-clock. |
updated_at | string? (date-time) | Order.last_update_time (string (date-time)) | not exposed | parse_datetime | kalshi: V1 GET: RFC3339, nullable in upstream — None when the order hasn’t been touched since creation. V2 mutation responses don’t echo it; the adapter sets Some(now()) on cancel paths and None on create paths. polymarket: Neither OpenOrder nor SendOrderResponse expose an updated_at field. The SDK doesn’t track it either. Always None. |
Source specs
- kalshi ·
schema/upstream/kalshi.openapi.yaml - polymarket ·
schema/upstream/polymarket-clob.openapi.yaml
Tables are auto-generated fromschema/mappings/. CI fails on unresolved $refs and on type mismatches fortransform: direct. Drift in upstream specs surfaces here on the daily refresh PR.

