Placing Orders
Place a market or limit order. Requires trade permission.
Polymarket-compatible execution model : On Polymarket, all orders are
limit orders — “market orders” are just limit orders with FOK
time-in-force at a marketable price. PolySimulator mirrors this exactly:
market orders fill at the best available price (BUY at best ask, SELL at
best bid), and the price field acts as a required worst-price limit
for slippage protection.
Market Orders
Executed immediately at the best available price — BUY at the best ask,
SELL at the best bid — matching how Polymarket fills market orders.
Worst-Price Limit (Required)
The price field is required on market orders and sets the worst price
you’ll accept. This is identical to Polymarket — there are no “blind” market
orders.
BUY : the order won’t fill above your price (you won’t overpay)
SELL : the order won’t fill below your price (you won’t undersell)
curl -X POST https://api.polysimulator.com/v1/orders \
-H "X-API-Key: $API_KEY " \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-bot-order-001" \
-d '{
"market_id": "0xabc123...",
"side": "BUY",
"outcome": "Yes",
"quantity": "10",
"order_type": "market",
"price": "0.68"
}'
FAK (Fill-and-Kill) Market Order
Use time_in_force: "FAK" for partial fills — buy what’s available up to
your quantity, cancel the rest. This is Polymarket’s FAK order type.
{
"market_id" : "0xabc123..." ,
"side" : "BUY" ,
"outcome" : "Yes" ,
"quantity" : "10" ,
"order_type" : "market" ,
"price" : "0.68" ,
"time_in_force" : "FAK"
}
Polymarket migration tip : FAK and IOC are equivalent in
PolySimulator. If your Polymarket bot uses FAK, it works here unchanged.
If you omit time_in_force, market orders default to FOK (Fill-or-Kill)
— the entire order fills or is cancelled.
Limit Orders
Queued and filled by the background matching engine (~1s polling cycle).
GTC (Good-Til-Cancel)
Persists until filled, cancelled by the user, or the market closes.
GTC Limit Order
Python (GTC)
{
"market_id" : "0xabc123..." ,
"side" : "BUY" ,
"outcome" : "Yes" ,
"quantity" : "10" ,
"order_type" : "limit" ,
"price" : "0.55" ,
"time_in_force" : "GTC"
}
FOK (Fill-or-Kill)
All-or-nothing immediate fill — matches Polymarket’s FOK order type.
If the full quantity can’t fill at the limit price, the entire order is cancelled.
FOK Limit Order
Python (FOK)
{
"market_id" : "0xabc123..." ,
"side" : "BUY" ,
"outcome" : "Yes" ,
"quantity" : "10" ,
"order_type" : "limit" ,
"price" : "0.55" ,
"time_in_force" : "FOK"
}
Attempts to fill on the next matching cycle (~1s). Any unfilled quantity is automatically cancelled — the order never persists in the book.
IOC Limit Order
Python (IOC)
{
"market_id" : "0xabc123..." ,
"side" : "BUY" ,
"outcome" : "Yes" ,
"quantity" : "10" ,
"order_type" : "limit" ,
"price" : "0.55" ,
"time_in_force" : "IOC"
}
When to use IOC : Sniping a specific price level without the risk of stale orders sitting in the book.
If the current market price is worse than your limit, the order cancels immediately.
Fill conditions:
BUY limit : Fills when market ask ≤ your limit price. Funds reserved upfront.
SELL limit : Fills when market bid ≥ your limit price. Shares reserved upfront.
Request Fields
Field Type Required Description market_idstring Yes Polymarket condition_id sidestring Yes BUY or SELLoutcomestring Yes Outcome label: Yes, No, or custom quantitystring Yes Number of shares as decimal string order_typestring No market (default) or limitpricestring Yes For limit orders: the limit price (0.01–0.99). For market orders: worst-price limit — required (Polymarket-style slippage protection) time_in_forcestring No GTC (default for limit), FOK (default for market), FAK, or IOCclient_order_idstring No Idempotency key
Time in Force
Value Description Polymarket Equivalent GTCGood-till-Cancelled — persists until filled, cancelled, or expired. Overridden to FOK for market orders. GTC FOKFill-or-Kill — all-or-nothing immediate fill (default for market orders) FOK FAKFill-and-Kill — fill available quantity, cancel remainder (Polymarket term) FAK IOCImmediate-or-Cancel — same behavior as FAK (PolySimulator alias) FAK
Response
{
"order_id" : 42 ,
"status" : "FILLED" ,
"order_type" : "market" ,
"side" : "BUY" ,
"outcome" : "Yes" ,
"price" : "0.65" ,
"quantity" : "10" ,
"notional" : "6.50" ,
"fee" : "0" ,
"filled_at" : "2026-02-06T12:00:45Z" ,
"price_source" : "clob_book" ,
"slippage_bps" : 15 ,
"account_balance" : "993.50" ,
"position" : {
"market_id" : "0xabc123..." ,
"outcome" : "Yes" ,
"quantity" : "10" ,
"avg_entry_price" : "0.65" ,
"status" : "OPEN"
}
}
Fill Diagnostics
Every market order includes transparency metadata:
Field Description price_sourceWhere the price came from: clob_book, clob_midpoint, gamma_api, redis_cache, matching_engine (limit order fill) slippage_bpsActual slippage from expected mid-price in basis points
Idempotency
Use the Idempotency-Key header or client_order_id field to prevent duplicate executions on retries:
curl -X POST https://api.polysimulator.com/v1/orders \
-H "Idempotency-Key: my-bot-2026-02-06-001" \
...
If the same key is submitted twice, the second request returns the result of the first execution without creating a new order.
Include a timestamp or sequence number in your idempotency key to make
debugging easier: "bot-alpha-20260206-001"
Error Handling
Status Error Code Meaning 400PRICE_REQUIREDMarket orders require a price field (worst-price limit) 400INSUFFICIENT_BALANCENot enough funds for this trade 400MARKET_CLOSEDMarket has resolved or is no longer accepting orders 400INVALID_QUANTITYQuantity must be a positive decimal string 401INVALID_API_KEYAPI key is invalid, expired, or revoked 403PERMISSION_DENIEDKey lacks trade permission 404MARKET_NOT_FOUNDUnknown market_id 409LIMIT_PRICE_NOT_METMarket price exceeds your worst-price limit 409IDEMPOTENCY_CONFLICTSame idempotency key with different order parameters 429RATE_LIMITEDToo many requests — check Retry-After header
resp = requests.post(
f " { BASE_URL } /v1/orders" ,
headers = { "X-API-Key" : API_KEY , "Idempotency-Key" : idempotency_key},
json = order_payload,
)
if resp.status_code == 200 :
order = resp.json()
print ( f "Order { order[ 'order_id' ] } : { order[ 'status' ] } @ { order[ 'price' ] } " )
elif resp.status_code == 400 :
err = resp.json()
if err.get( "error" ) == "PRICE_REQUIRED" :
print ( "Add a 'price' field — market orders require a worst-price limit" )
elif err.get( "error" ) == "INSUFFICIENT_BALANCE" :
print ( "Not enough funds — current balance too low" )
else :
print ( f "Order rejected: { err.get( 'message' , err) } " )
elif resp.status_code == 409 :
err = resp.json()
if err.get( "error" ) == "LIMIT_PRICE_NOT_MET" :
print ( f "Price moved beyond your limit — retry with a wider price" )
else :
print ( f "Conflict: { err.get( 'message' , err) } " )
elif resp.status_code == 429 :
retry_after = int (resp.headers.get( "Retry-After" , 1 ))
time.sleep(retry_after)
Next Steps