Skip to main content

Polymarket Raw-HTTP Endpoints

PolySimulator exposes the exact path + payload shapes Polymarket’s public CLOB API uses. SDK clients written against https://clob.polymarket.com (e.g. py-clob-client, @polymarket/clob-client) can be pointed at PolySimulator by changing only the base URL and credentials — no payload rewrites, no field renames.
This page covers the raw-HTTP shape only. PolySimulator also offers two simpler shapes for new code:
  • POST /v1/orders — native (market_id + outcome + quantity + price + time_in_force). See Placing Orders.
  • POST /v1/clob/order — legacy SDK convenience (token_id + side
All three paths funnel through the same matching engine; pick by integration shape, not by behaviour.

Order Placement

POST /v1/order — single order

Mirror of Polymarket’s POST /order. Request body:
Maker/taker amount conversion (load-bearing — get this wrong and notional sizing is silently broken): PolySimulator follows Polymarket’s 6-decimal fixed-point convention for both USDC and outcome-token amounts: Example: BUY 1 share at $0.50 ⇒ makerAmount=500000, takerAmount=1000000. On-chain fields are accepted and ignored: salt, maker, signer, taker, nonce, feeRateBps, signatureType, signature, timestamp, metadata, builder. PolySimulator is paper trading — there is no chain to settle against. orderType enum: GTC | FOK | FAK | GTD. We don’t support good-til-date natively; GTD coerces to GTC so SDK callers get a working order rather than a 422. Response:
status enum on write (POST /v1/order, POST /v1/orders): live (resting on book) / matched (filled immediately) / unmatched (rejected). PolySimulator does not return PM’s delayed status — we don’t delay matching.
Status enum split between write and read endpoints. The write-side returns lowercase short forms (live / matched / unmatched) — that’s PM’s SendOrderResponse contract.The read-side (GET /v1/data/orders, GET /v1/order/{id}) returns PM’s OpenOrder.status enum — PM’s exact members:The ?status= filter accepts the single-L ORDER_STATUS_CANCELED spelling as well as the double-L ORDER_STATUS_CANCELLED alias.This mirrors Polymarket’s real CLOB exactly — the two enums come from different protobufs in PM’s internal codebase. SDK clients should treat them as separate types and map between them at the application layer (@polymarket/clob-client does this internally; raw fetch users need to do it themselves).

TypeScript / Node example

TypeScript users: the PolySimulator API Mintlify spec is auto-generated from the live OpenAPI; if you’re using openapi-typescript to generate types, run it against https://docs.polysimulator.com/openapi.json (auto-rebuilds on every deploy).

POST /v1/orders — single object or PM batch array

POST /v1/orders dispatches on the JSON body type:
  • A JSON object is the native single order: {market_id, side, outcome, quantity, order_type, price, time_in_force}.
  • A JSON array is a Polymarket-shape batch of up to 15 PmSendOrderRequest entries — each entry is validated and executed independently (per-entry failure isolation, matching PM’s “failures in one entry do not abort the others” contract). A malformed entry surfaces as a failed result at its array index rather than rejecting the whole batch. More than 15 entries returns 400.
For a PM-shape single order you can also use POST /v1/order (singular):

Order Lifecycle

GET /v1/data/orders — list user’s orders, PM envelope

Polymarket-shaped OrdersResponse:
Pass next_cursor back as ?next_cursor=... (PM’s request param — what py-clob-client sends) or the ?cursor=... alias to paginate. Cursor is urlsafe-base64 and opaque; the SDK’s initial MA== seed and the LTE= terminal sentinel both behave exactly as on real PM. Default scope matches PM: OPEN orders only. Pass the polysim-extension ?status= param (ORDER_STATUS_MATCHED, ORDER_STATUS_CANCELED, ALL, or friendly aliases like matched / canceled) to read history. Filters: id, market, asset_id (token id — resolves to the market+outcome and filters both), status, before / after (unix-seconds timestamps, PM convention; ISO accepted as an extra; garbage returns 400 instead of being silently dropped), limit (max 500).

GET /v1/order/{orderID} — single order

Returns a single OpenOrder with the same shape as data[] above. Hex order IDs (PM uses on-chain hashes; we use integer DB ids serialised as strings) cleanly 404 with error: ORDER_NOT_FOUND instead of crashing.

DELETE /v1/order — cancel by body

Returns {canceled: ["6391"], not_canceled: {}} — PM’s exact shape.

DELETE /v1/orders — bulk cancel (array body)

Up to 100 ids per request (PM’s documented cap is 3,000; the PolySimulator cap is lower during the beta period). Invalid ids appear in not_canceled with an explanation.

POST /v1/cancel-all — cancel all open orders

No body. Returns the same {canceled, not_canceled} envelope.

Read Endpoints (public — no auth)

These mirror Polymarket’s public market-data endpoints. All return the exact shape PM emits.
Field-type details:
  • GET /v1/tick-size/{token_id} returns minimum_tick_size as a JSON number (0.01), matching live Polymarket. Note that the tick_size field inside a /v1/book snapshot is a string — see String Numerics.
  • GET /v1/time returns a bare integer (1779147906), not a {"server_time": ...} object — this matches Polymarket’s wire.
Spread cap: PolySim mirrors Polymarket’s documented behaviour of capping reported spread at $0.10. Markets with a bid=0.001 ask=0.999 book report spread="0.10", not 0.998. This stops arbitrage filters from treating every illiquid book as a free-money signal.

Tick-Size Enforcement

PolySimulator rejects limit orders whose price doesn’t conform to the market’s minimum tick size — exactly as Polymarket does.
Always quantise client-side using the result of GET /v1/tick-size/{token_id} before submitting. SDKs that already implement PM’s quantisation (e.g. py-clob-client.utilities.price_valid) work without modification. Market orders use price as a slippage bound, not a strict price, so off-grid price values are not tick-rejected on market orders.

Beta Cohort Header

Beta-issued keys carry X-API-Beta-Cutoff: expired on every response once the cohort cutoff date passes. SDKs can treat this header as the signal to enter read-only mode:
Public cohort status (no auth required):

SDK Migration Checklist

Porting a py-clob-client bot? Three lines of config:
@polymarket/clob-client (TypeScript) is the same: change host, swap auth headers. salt, signer, signature continue to be generated client-side and ignored server-side — no SDK changes needed.

Next Steps