Skip to main content
See API keys for format, scope taxonomy, associatedWallet requirement, and rate-limit buckets.

Request body

The request body is whitelisted (forbidNonWhitelisted); any extra field returns 400 validation_failed. maker is the vault address. The signing EOA is recovered from signature and must satisfy vaultFactory.vaultOf(signer) == maker. The backend re-runs that check before storing the order, so passing the EOA in maker instead of the vault returns 400 bad_signature.

Validation rules

Worked example — BUY 2 YES at 0.42

Response shape

The clientOrderId field is echoed verbatim when the request supplied one — present on every shape (success, REJECTED, idempotent replay). Use it to correlate the server-issued orderId to your own client-side handle without a follow-up GET /api/orders/{id}. The same value is also carried on the events.order_placed and events.order_cancelled frames over /ws/user, so partners that drive their state machine off the WS feed get the correlation key on both surfaces.

Batch placement

Submit up to 10 orders in one request with POST /api/orders/place-batch. Each entry is the exact same body as single placement; the batch is processed sequentially in array order with independent per-order outcomes — one rejected order never aborts the rest, and there is no all-or-nothing atomicity.
The response is an array aligned to the request by index. Each item is a PlaceOrderResp (identical to single place) plus a success flag:
Per-wallet limits accumulate across the batch. KYC deposit-tier, responsible-gambling, and partner trade caps are charged against the running total of accepted entries, so a batch can never admit more exposure than the same orders sent one at a time.
Business reject vs infrastructure failure. A rejected order (bad signature, insufficient funds, …) is a per-entry success: false with HTTP 200 — the rest of the batch still processes. An infrastructure failure (matcher / verifier / DB unavailable) fails the whole request with a 5xx. On a 5xx, retry the whole batch: every forwarded entry carries a clientOrderId (the server mints one when you omit it), so the replay returns the already-committed result via idempotency rather than placing duplicates.
Rate limited at 5 req/sec/wallet (up to 50 orders/sec). KYC deposit-tier gating applies, same as single place.

Post-only orders

Set postOnly: true to guarantee an order only ever rests on the book and never matches on entry. It’s the maker-side guarantee market makers need to avoid paying taker fees or accidentally crossing their own quotes.
Only valid for LIMIT orders with gtc time-in-force (optionally with expiry). Omit it (or send false) for today’s behavior.
Two rejection modes.
  • post_only_invalid_order_type (HTTP 400) — postOnly was sent with a MARKET order or an ioc / fok time-in-force. The combination is invalid; nothing is placed.
  • post_only_would_cross — the order was marketable at entry: its price meets or crosses the best price on the opposite side of the book (at-touch equality counts as crossing). It returns { "status": "REJECTED", "code": "post_only_would_cross" } with no fills — reprice inside the spread and resubmit.

Sell orders

Same shape; side: 'sell'. Balance is not locked for SELL orders — the outcome token (ERC-1155) must already sit in the vault, not the EOA. Position resolution is keyed by maker (the vault), which is why on-chain splits (USDC → YES + NO) must be initiated by vault.splitPosition(...) rather than by the EOA directly. See Vaults for the split flow.

Next

Time-in-force

GTC vs IOC vs FOK behaviour.

Cancelling orders

Single-order and cancel-all flows.