Skip to main content
The Markets API exposes indicative per-outcome prices, and POST /v1/orders accepts per-share price guards on market orders so you can bound the price you actually fill at. This page explains how to read those prices and which guards to set on each venue.

Units: one scale across every venue

ParlayX normalizes units so you work with the same scale no matter which venue a market lives on: Size every order with exactly one of amount or shares (supplying both, or neither, is rejected):
  • amount (USDC) works for any order. ParlayX converts it to each venue’s native representation when it routes your order.
  • shares (outcome contracts) is supported on sells and limit orders only — a market BUY is sized in USDC notional by the venue, so it must use amount.
Either way you never deal with venue-native base-unit scaling — ParlayX handles the conversion when it routes.

Per-outcome prices: bid, mid, and ask

GET /v1/markets/{marketVenue}/{marketId} and GET /v1/markets/match return a MarketOutcome for each side of the market, with indicative prices expressed as implied probability (0–1). The single-market endpoint returns the full bid / mid / ask; match returns mid only, so read prices from the single-market endpoint when you need bid/ask to set guards: Example response fragment:
The spread (ask − bid) is your worst-case round-trip cost. Wider spreads mean less liquidity — size your per-share guard accordingly.
bid, mid, and ask are indicative snapshots from the venue at read time. They are not a quote and do not guarantee a fill at that price — use them to set the per-share guards described below.

Controlling fill price on a market order

Market orders ("type": "market") submitted through POST /v1/orders accept per-share guards that cap how badly your fill can slip from the price you saw when you decided to trade. The exact field depends on the venue. To rest at a fixed price instead, submit a limit order ("type": "limit") with a limitPrice.

Polymarket market orders

Polymarket market orders accept both FOK (fill-or-kill) and FAK (fill-and-kill, partial allowed) and expose two optional per-share guards:
  • maxFillPrice — per-share cap for a BUY. Fills come back at or below it. If omitted, the buy is bounded only by amount (no per-share cap).
  • minFillPrice — per-share floor for a SELL. Fills come back at or above it. If omitted, a default slippage floor (currently 2% below the prevailing midpoint) is applied.
Both are implied probabilities in the open interval (0, 1). Use ask to set a tight buy cap, and bid to set a tight sell floor:
A typical pattern is to read the outcome, then submit with maxFillPrice = ask + tolerance on a BUY (or minFillPrice = bid − tolerance on a SELL) where tolerance is your acceptable slippage budget.

Limitless market orders

Limitless market orders are FAK (fill-and-kill, partial allowed) and work for both BUY and SELL. They take the same optional per-share guards as Polymarket: maxFillPrice caps a BUY, minFillPrice floors a SELL. The difference is the default: when you omit the guard, the executor reads the live quote and applies a 50bps headroom (ask × 1.005 for a BUY, bid × 0.995 for a SELL) rather than leaving the order uncapped. For a resting order with an explicit bound, submit a limit order (timeInForce: { "type": "GTC" } or { "type": "GTD" }) with a limitPrice. A "GTD" order carries its expiresAt (ISO-8601, UTC) inside the timeInForce object, after which the venue auto-cancels it.
Every Limitless order requires the marketId — the same value the Markets API returns — in addition to outcomeId. Omitting it fails the request with a 400 invalidRequest.

Choosing prices in practice

  1. Call GET /v1/markets/{marketVenue}/{marketId} and read bid, mid, ask on the outcome you want to trade.
  2. Decide your slippage tolerance — e.g. 2 cents per share.
  3. Submit the order with the venue-appropriate guard:
    • BUY → maxFillPrice = ask + tolerance
    • SELL → minFillPrice = bid − tolerance
    • On Limitless, omitting the guard is also fine: the executor derives one from the live quote with a 50bps headroom.
  4. Inspect the resulting fill via GET /v1/orders/{orderId}. Each market order reports filledAmount and the averagePrice so you can reconcile against the guard you set.
If a venue cannot fill within your guard, the order is rejected with a PRICE_EXCEEDED error code on the market order rather than partially filling at a worse price.

Stop orders (conditional)

A stop ("type": "stop") is a market order plus a price trigger. Nothing rests on the venue while it waits: ParlayX watches the market’s top of book and, when the reference price crosses your triggerPrice, fires a market child order for you. It is certain to fire once the level is crossed, but — like any market order — the fill price is not guaranteed. The watch direction comes from side, so there is no separate direction field: Two parameters govern the trigger:
  • triggerPrice — the level (0–1 implied probability) the reference must cross.
  • triggerFillDepth (optional, default 1) — the cumulative resting size (in outcome shares) that must sit past the level before firing. The default fires on touch; a larger value waits for that much fillable depth, filtering a thin quote that pokes through the level on negligible size.
The child carries the market time-in-force set (Polymarket FOK/FAK, Limitless FAK). If the market gaps straight through the level, the child still fills at the next available price (a thin book may partially fill at the default depth).
A stop can be submitted on its own or batched with other market orders under one orderId. The response is the same { "orderId": "..." } as any submission; that id is the only handle you need for Get Order and Cancel Order. Reading it back returns an order whose single marketOrders entry is type: "stop", carrying conditionalStatus; once it fires, the order it places is rolled up onto that entry (status/filledAmount/averagePrice), so there is no second id to chase — see Conditional orders for the full shape. Cancelling before the trigger fires removes the watch and rests nothing; after it fires, cancelling the same orderId cancels the order it placed.

Stop-limit orders (conditional)

A stop-limit ("type": "stop_limit") shares the exact trigger of a stop, but fires a limit child that rests at a price you set rather than a market child. The trigger — reference side, cross direction, triggerPrice, triggerFillDepth — is identical to a stop (see the table above); the difference is what happens on activation:
  • A stop fires a market child: certain to fill once the level is crossed, but at whatever price the book offers.
  • A stop-limit fires a limit child that rests at your limitPrice: the fill price is guaranteed, but the fill itself is not — if the market gaps past your limit, the child rests unfilled until the price comes back (or you cancel it).
In addition to the stop’s trigger parameters, a stop-limit requires a child limitPrice (0–1 implied probability) — the price the fired limit order rests at. Its time-in-force is the resting limit set, GTC or GTD, on both venues (a fill-and-kill child would defeat the point of a resting limit).
Like a stop, a stop-limit can stand alone or be batched with other market orders; it reads back as a marketOrders entry of type: "stop_limit", carrying conditionalStatus; once fired, the resting limit it places is rolled up onto that entry — so its status can sit partial/open until the limit fills, under the one orderId you already hold. A GTD child’s expiresAt is fixed at submit time but the child only rests once the trigger fires, so a GTD whose expiry has already passed by fire time is rejected by the venue; prefer GTC (or a generous expiry) for triggers that may sit armed for a while. Cancellation works as for a stop: before the trigger the watch is removed; after, cancelling the same orderId cancels the resting limit it placed.