States
Resolved, Voided, and Closed are terminal. Paused is transient — orders stick around.
Transitions you’ll see in production
Active market, the response is 422 Unprocessable Entity with body {"error": "market is not active (status: Pending)"} (or Paused, Resolved, etc.).
Order entry on a non-Active market
Order placement returns 422 with a stable error prefix:"market is not active" to detect this case generically across all non-Active statuses.
WebSocket: MarketStatusChanged
The combined/ws channel emits a market_status_changed frame on every transition:
cancelled_orders is non-zero only on terminal transitions (Resolved, Voided, Closed). On a Paused transition it’s always 0 — Paused retains resting orders.
On terminal transitions, /ws/user subscribers also receive one order/CANCELLATION frame per cancelled order owned by the user, fanned out before the market_status_changed frame.
Claimable positions
Once a market reachesResolved or Voided, the user’s positions become claimable. Query GET /claimable?address=<addr>:
refund_reason:
resolved_winner— Market resolved with a definite winner; this side won.voided_refund— Market was invalidated. Both YES and NO holders get pro-rata refunds; both sides appear here when held.
ConditionalTokens.redeemPositions call made by the smart account through the XO bundler; the orderbook does not move funds — it tells you what you can claim. See Redeem positions.
On-chain, payouts are reported when the market is closed (after the resolution period). redeemPositions reverts until payoutDenominator(conditionId) is non-zero, even if /claimable already lists the position.
Pending → Active
Markets created on-chain through the protocol enterPending. The matching engine activates them when the on-chain MarketCreated event is observed and any required setup completes. Once Active, the market is queryable via /markets/{condition_id} with "active": true.
A Pending market with token IDs visible in /markets is a normal intermediate state — not an error.