Orders & Execution Graphs
Every order is an execution graph. A simple market buy is a 1-node graph. A multi-leg hedge is a multi-node graph with dependency edges. One endpoint handles both.
Submit Order
/v1/ordersAccepts two formats: simple order (auto-wrapped into a 1-node graph) or full execution graph.
Simple Order
{
"symbol": "BTC-USD",
"side": "buy",
"qty": 0.1
}Prediction-market simple orders use the same endpoint. symbol can be a Polymarket slug, :yes / :no slug, raw token ID, or a full polymarket.com/event/... URL.
Optional fields:
| Field | Type | Description |
|---|---|---|
symbol | string | Required. Trading pair, Polymarket slug, token ID, or full Polymarket event URL |
side | string | Required. buy or sell |
qty | number | Required. Quantity in human units (e.g., 0.1 = 0.1 BTC) |
price | number | Limit price. Omit for market order. |
venue | string | Pin to specific venue. Omit for SOR routing. |
Full Execution Graph
{
"nodes": [
{
"node_id": "spot",
"instrument": {"symbol": "ETH-USD", "type": "spot"},
"side": "buy",
"order_type": "market",
"quantity": {"fixed": {"qty_1e8": 20000000000}},
"execution": {"policy": "sor", "urgency": "medium"},
"activation": "root"
},
{
"node_id": "hedge",
"instrument": {"symbol": "ETH-USD-PERP", "type": "perp", "venue": "hyperliquid"},
"side": "sell",
"order_type": "market",
"quantity": {"fixed": {"qty_1e8": 20000000000}},
"execution": {"policy": "aggressive_chase"},
"activation": "wait"
}
],
"edges": [
{
"edge_id": "e0",
"from_node": "spot",
"to_node": "hedge",
"trigger": "on_fill_ratio",
"condition": {"fill_ratio_gte": 0.5}
}
],
"risk": {
"admission": {"max_notional_usd": 500000},
"runtime": {"max_loss_usd": 10000}
},
"is_sandbox": false
}Node Fields
| Field | Type | Description |
|---|---|---|
node_id | string | Unique ID within the graph |
instrument.symbol | string | Trading pair, or Polymarket slug / token ID / full event URL |
instrument.type | string | spot, perp, or prediction. Polymarket slug/URL inputs are auto-normalized to prediction before routing. |
instrument.venue | string | Pin to venue (optional) |
side | string | buy or sell |
order_type | string/object | "market" or {"limit": {"price_1e9": N}} |
quantity | object | {"fixed": {"qty_1e8": N}} or "derived" |
execution.policy | string | sor, ioc_sweep, passive_limit, aggressive_chase, passive_ladder, time_drip |
execution.urgency | string | low, medium, high |
execution.max_slippage_bps | int | Max slippage in basis points |
execution.horizon_ms | int | Execution time horizon |
execution.tif | string | GTC, IOC, FOK |
execution.pacing | object | TWAP: {"uniform": {"num_slices": 10, "interval_ms": 30000}} |
activation | string | root (start immediately) or wait (wait for edge trigger) |
Response
{
"graph_id": "graph_7d769677a7b4448b...",
"status": "active",
"node_count": 2,
"edge_count": 1
}For Polymarket, /v1/orders resolves the symbol to the venue token ID server-side before the execution graph is submitted. You do not need to pre-resolve token IDs yourself.
Get Graph Status
/v1/execution_graphs/{graph_id}{
"graph_id": "graph_7d769...",
"client_id": "client_abc",
"status": "active",
"nodes": {
"spot": {
"status": "filled",
"target_qty_1e8": 20000000000,
"filled_qty_1e8": 20000000000,
"avg_fill_price_1e9": 2325530000000,
"fill_count": 3
},
"hedge": {
"status": "executing",
"target_qty_1e8": 20000000000,
"filled_qty_1e8": 10000000000,
"avg_fill_price_1e9": 2324800000000,
"fill_count": 1
}
},
"edges": {
"e0": {"status": "fired", "fired": true}
}
}Graph status values: active, completed, cancelled, failed, paused.
Node status values: pending, executing, filled, partial_fill, cancelled, rejected, failed.
Transient vs terminal failures
The router distinguishes transient failures (worth retrying) from terminal rejects (don't retry — fix the input first). Inspect traces on the order to see the underlying classification:
| Trace event | Meaning | Client action |
|---|---|---|
EXCHANGE_REJECT with code: 429 or 5xx body | Venue rate-limited or transient outage. The router automatically backs off + retries; the parent order stays executing. | Wait — no client action. |
EXCHANGE_REJECT with "market metadata not yet indexed (gamma)" | Polymarket-only: the token's market hasn't been indexed by Gamma yet. The edge refused to sign with placeholder defaults that would silently produce invalid signature. | Retry in ~30 s. Gamma typically catches up within minutes. |
EXCHANGE_REJECT with "Size (N) lower than the minimum: M" | Venue business-rule reject (e.g. Polymarket's 5-share minimum, Kalshi tick-size). | Fix the order shape and resubmit. |
EXCHANGE_REJECT with "invalid signature" | Venue rejected the signature. Should be very rare post-deploy — the edge guards against the placeholder-spec class. If you see this on a known-active market, surface it. | Surface to support. |
List Orders
/v1/orders| Param | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max results |
offset | int | 0 | Pagination offset |
symbol | string | — | Filter by symbol |
node_order_id | string | — | Filter by specific order ID |
{
"orders": [
{
"node_order_id": "graph:graph_7d769...:spot:1",
"client_id": "client_abc",
"side": "BUY",
"symbol": "ETH-USD",
"qty_1e8": 20000000000,
"filled_qty_1e8": 20000000000,
"status": "COMPLETED",
"created_unix_ns": 1776208527263141000,
"updated_unix_ns": 1776208529872926000,
"failure_reason": null
}
],
"total": 42,
"limit": 50,
"offset": 0,
"has_more": false
}Status and side values are UPPERCASE in order responses: BUY, SELL, COMPLETED, FAILED.
Cancel Order / Graph
/v1/execution_graphs/{graph_id}Cancels all active nodes in the graph. Returns 200 on success.
To cancel a specific order, extract the graph_id from the node_order_id:
node_order_id: "graph:graph_7d769...:spot:1"
^^^^^^^^^^^^^^^^
graph_id
Resume Paused Graph
/v1/execution_graphs/{graph_id}/resumeResumes a paused graph. Pending nodes will re-evaluate their edge triggers.
Amend Graph Node
/v1/execution_graphs/{graph_id}/nodes/{node_id}Amend a running graph node's execution parameters (urgency, slippage, horizon):
{
"qty_1e8": 15000000000,
"urgency": "high",
"max_slippage_bps": 25,
"horizon_ms": 5000
}All fields are optional. Only provided fields are updated.
Amend Order (uniform verb)
/v1/orders/{node_order_id}Venue-agnostic price/qty amend. Designed for prediction markets (Kalshi + Polymarket) and spot CEX venues behind one call. The graph-level API executes through the parent-order amend / cancel-replace workflow today; Kalshi's lower-level transport supports native atomic /portfolio/orders/{id}/amend, but CC does not yet preserve that native amend path end-to-end through this endpoint.
{
"new_qty_1e8": 12000000000,
"new_constraints": {
"max_price_1e9": 550000000
}
}| Field | Description |
|---|---|
new_qty_1e8 | New total quantity (not a delta). Omit to keep current. |
new_constraints.max_price_1e9 | New limit price. Omit to keep current. |
At least one of new_qty_1e8 / new_constraints.max_price_1e9 must be present.
Response:
{
"node_order_id": "graph_abc...:node_0:2",
"status": "accepted"
}The SDK wraps this and surfaces a mode field (cancel_replace today) so queue-sensitive market makers can branch on execution mode.
Decrease Order (uniform verb)
Shrink a resting order's remaining size without touching its price. SDK-only verb (no distinct REST endpoint today — the SDK reads the current size, computes new_qty, and issues a regular amend). Kalshi's lower-level transport supports native /portfolio/orders/{id}/decrease, but CC does not yet preserve that native decrease path end-to-end through this SDK method, so the SDK reports cancel_replace_shrink today.
r = seq.decrease(order_id, reduce_by=5.0)
# {"order_id": "...", "mode": "cancel_replace_shrink", "status": "accepted"}Batch Orders (uniform verb, SDK-orchestrated)
The SDK batch() builder collects submits/cancels for a target venue and flushes graph roots together. Today the graph-level SDK path serializes and returns mode="serial" for both Kalshi and Polymarket.
The lower venue transports support native batches where the execution engine preserves a transport batch window: Kalshi uses /portfolio/orders/batched (20-op atomic) and Polymarket uses CLOB POST /orders (15 orders, per-order result). Those native paths are not yet surfaced by this SDK graph builder, so queue-sensitive callers must branch on the returned mode.
# Kalshi — works directly, mode=serial today
with seq.batch("kalshi") as b:
b.buy_limit("KXBTCZ-26DEC31-T99000", 10, 0.55)
b.cancel(stale_id)
# Polymarket — graph-level SDK batch is serial today
seq.batch("polymarket").buy("TOKEN_ID", 10).end()
# → {"mode": "serial", "responses": [...]}Redeem Prediction Market
/v1/markets/{slug}/redeem?venue={venue}Uniform settlement claim. Kalshi auto-settles (returns mode="auto_settled", no action taken); Polymarket fires an authenticated POST to the CLOB relayer (returns mode="relayer_submitted"). See Prediction Markets for full response shape.
List Fills
/v1/fills| Param | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max results |
offset | int | 0 | Pagination offset |
symbol | string | — | Filter by symbol |
node_order_id | string | — | Filter by order |
Each fill carries a Phase-1 TCA breakdown when the venue reported one:
| Field | Description |
|---|---|
fee_1e9 | Realized fee in USD scaled to 1e9. Authoritative for accounting — use this, not the pre-trade estimate. |
is_maker | true if liquidity-providing leg, false if taker, null if the venue didn't classify. |
fee_breakdown | Structured commission decomposition (JSONB). Keys: commission_1e9, commission_asset (e.g. "USD", "USDC"), and per-component fields where applicable. null for fills from older code paths. |
taker_fee_bps_applied, maker_fee_bps_applied | Realized rate (in bps) the venue actually charged on this fill — useful for TCA prediction-error vs expected_fee_bps set at submit. |
commission_asset | What unit the fee was charged in (USD for Kalshi, USDC for Polymarket / Polygon CTF, etc.) |
venue_reported_cum_fee_1e9 | Running cumulative commission per the venue's accounting (drift check against sum(fills.fee_1e9)). |
Polymarket fills now carry the realized fee derived from the venue's
fee schedule (fd.r × C × p × (1-p) keyed by the trade's asset_id).
Earlier TCA / accounting reports may have under-counted Polymarket fees
because the WS event doesn't include fee_rate_bps per-leg and the old
code coerced absent → 0. Cross-check against expected_fee_bps
(snapshot at submit) for prediction-error analysis.
Kill Switch
/v1/kill_switchEmergency circuit breaker. Cancels all active orders and blocks new submissions.
{"active": true, "reason": "risk limit breach"}To clear: {"active": false}
Execution Policies
| Policy | Behavior |
|---|---|
sor | Smart order routing — splits across best venues (default) |
ioc_sweep | Single immediate-or-cancel sweep |
passive_limit | Post at touch, hold until TTL |
aggressive_chase | Cross spread, widen on timeout |
passive_ladder | Post passively, escalate after horizon_ms |
time_drip | SOR picks tactic based on urgency + spread |
Edge Triggers
| Trigger | Fires when |
|---|---|
on_accepted | SOR acknowledges the order |
on_first_fill | First fill arrives |
on_fill | Every fill (streaming hedge mode) |
on_fill_ratio | Fill ratio reaches condition.fill_ratio_gte |
on_full_fill | 100% filled |
on_timeout | {"on_timeout": {"ms": 5000}} |
on_price | Price condition: {"on_price": {"symbol": "BTC-USD", "direction": "below", "reference": "graph_entry_price", "offset_pct": -5.0}} |
on_cancel | Parent cancelled |
on_done | Any terminal state |