Place Order Dispatcher
Dispatcher: PolySim native single (JSON object) OR PM batch (JSON array).
See module-level comment above for the path-mapping rationale.
Authorizations
Issue from /v1/keys (or admin-issued for enterprise tier).
Headers
Your PolySimulator API key
Polymarket-CLOB-compat alias for X-API-Key (underscore form). SDK clients ported from Polymarket can authenticate without changing header names. X-API-Key takes precedence when both are provided.
PM-CLOB-compat dashed-form alias for X-API-Key. Same value semantics as POLY_API_KEY but with HTTP-conventional dash separators. Audit P1 (staging audit 2026-05-16 0817 PR #1296): the per-tier middleware accepts both spellings but the auth dependency originally only matched the underscore form — now both work end-to-end.
PM-CLOB-compat: Authorization: Bearer ps_live_... (or ps_test_...) is accepted as an alias for X-API-Key so py-clob-client and other ported SDKs authenticate without header name changes. Bearer JWTs are NOT accepted here — use the dashboard-auth endpoints for those.
Body
- PlaceOrderRequest · object
- PmSendOrderRequest · object[]
Polymarket condition_id
256BUY, SELL Outcome label, e.g., Yes or No
200Number of shares as decimal string, e.g. '10.5'. Required UNLESS amount is provided (BUY market orders only — Polymarket convention).
USD amount to spend, as decimal string (e.g. '10.50'). Polymarket convention for BUY market orders: amount=5 means 'spend $5' (versus our quantity=5 which means 'buy 5 shares ≈ $5 × current_price'). Only valid when side=BUY and order_type=market; the handler derives quantity = floor4(amount / price) using the caller-supplied worst-price limit in the price field (NOT the eventual fill price). This is conservative: the trade can't spend more than amount USD even at the worst acceptable price; a better fill means more shares. The result is rounded down to 4 decimal places (the matching engine's share quantum) and capped at the per-trade share limit. For SELL or limit orders, use quantity (shares). Mutually exclusive with quantity — supplying both is a 400 error.
Order type
market, limit For limit orders: the limit price (0.01-0.99, required). For market orders: the worst acceptable price — Polymarket-style slippage protection (required). BUY won't fill above this price; SELL won't fill below it. All market orders are effectively marketable limit orders, matching Polymarket's execution model.
GTC = Good-Til-Cancel (default for limit orders, persists until filled/cancelled), FOK = Fill-Or-Kill (default for market orders — all-or-nothing, matching Polymarket), FAK = Fill-And-Kill (Polymarket term for partial fill, cancel remainder — equivalent to IOC), IOC = Immediate-Or-Cancel (partial fill, cancel remainder), GTD = Good-Til-Date (resting limit auto-expiring at expiration; rolling out — accepted only while ORDER_SEMANTICS_PM_V2_ENABLED is on)
GTC, FOK, FAK, IOC, GTD Idempotency key
256Unix-seconds expiration timestamp — required for time_in_force=GTD (PM convention: the order auto-cancels once the timestamp passes), ignored for every other TIF. Rolling out behind ORDER_SEMANTICS_PM_V2_ENABLED.
Polymarket's postOnly: the order must REST on the book — if it would cross the spread (marketable at placement) it is rejected with 400 INVALID_POST_ONLY_ORDER instead of executing, guaranteeing maker-side execution. Only valid for limit orders with GTC/GTD time-in-force (FOK/FAK/IOC/market combinations are rejected with INVALID_POST_ONLY_ORDER_TYPE, matching PM). Rolling out behind ORDER_SEMANTICS_PM_V2_ENABLED; advisory (ignored) until the flag is on.
Multi-wallet (May 8 launch). When set to a SANDBOX wallet the user owns, the trade debits/credits Wallet.balance directly and the resulting Order is tagged with trade_source='ui_sandbox' (excluded from the public leaderboard). When set to a MAIN/API wallet the user owns, the cash flow is routed to that explicit wallet (otherwise we default to API for /v1/orders). Omit for legacy back-compat behaviour: cash flows to the user's API wallet.
Response
Object body → OrderResponse (PolySim single-order) OR OrderAck when the user routes through Order Pipeline V2 (per-user allowlist or global flag — ack-then-reconcile, no fill data in the body; clients poll GET /v1/orders/{order_id} for the post-reconcile fill fields). Array body → List[PmSendOrderResponse] (PM batch, max 15). The OrderAck schema is registered under /v1/orders/{order_id} (DELETE)'s 202 response.
- OrderResponse · object
- OrderAck · object
- PmSendOrderResponse · object[]