> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parlayx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pricing and Execution

> Read per-outcome prices and control the price your orders fill at

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:

| What                                                                       | Unit                       | Notes                                                           |
| -------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------- |
| Prices (`bid`, `mid`, `ask`, `maxFillPrice`, `minFillPrice`, `limitPrice`) | Implied probability, `0–1` | Identical scale on every venue.                                 |
| Order size (`amount`)                                                      | USDC                       | Up to 6 decimal places (micro-USDC).                            |
| Order size (`shares`)                                                      | Outcome shares (contracts) | Up to 6 decimal places. An alternative to `amount` — see below. |

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:

| Field | Meaning                                              | Use when                                                       |
| ----- | ---------------------------------------------------- | -------------------------------------------------------------- |
| `bid` | Best executable price to **sell** this outcome into. | Pricing a SELL — fills land at or above the bid.               |
| `ask` | Best executable price to **buy** this outcome at.    | Pricing a BUY — fills land at or below the ask.                |
| `mid` | Midpoint between bid and ask.                        | Display, P\&L marks, slippage estimates. Not a tradable price. |

Example response fragment:

```json theme={null}
{
  "name": "Yes",
  "outcomeId": "0x...",
  "bid": 0.54,
  "mid": 0.55,
  "ask": 0.56
}
```

The spread (`ask − bid`) is your worst-case round-trip cost. Wider spreads
mean less liquidity — size your per-share guard accordingly.

<Note>
  `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.
</Note>

## 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:

```json theme={null}
{
  "marketOrders": [
    {
      "venue": "polymarket",
      "type": "market",
      "outcomeId": "713210...",
      "side": "buy",
      "amount": 50,
      "timeInForce": { "type": "FOK" },
      "maxFillPrice": 0.57
    }
  ]
}
```

```json theme={null}
{
  "marketOrders": [
    {
      "venue": "polymarket",
      "type": "market",
      "outcomeId": "713210...",
      "side": "sell",
      "amount": 50,
      "timeInForce": { "type": "FAK" },
      "minFillPrice": 0.53
    }
  ]
}
```

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.

<Note>
  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`.
</Note>

```json theme={null}
{
  "marketOrders": [
    {
      "venue": "limitless",
      "type": "market",
      "marketId": "...",
      "outcomeId": "...",
      "side": "buy",
      "amount": 20,
      "timeInForce": { "type": "FAK" }
    }
  ]
}
```

## 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:

| `side` | references   | fires when the price                | typical use                              |
| ------ | ------------ | ----------------------------------- | ---------------------------------------- |
| `sell` | best **bid** | **falls** to/through `triggerPrice` | stop-loss protecting a long              |
| `buy`  | best **ask** | **rises** to/through `triggerPrice` | stop protecting a short / breakout entry |

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).

```bash theme={null}
# Stop-loss: sell out of a long if the bid falls to 0.35.
curl -X POST https://api.parlayx.com/v1/orders \
  -H "x-api-key: $PARLAYX_API_KEY" \
  -H "Idempotency-Key: stop-2026-06-24-001" \
  -H "Content-Type: application/json" \
  -d '{
    "marketOrders": [
      {
        "venue": "polymarket",
        "type": "stop",
        "outcomeId": "713210...",
        "side": "sell",
        "shares": 100,
        "timeInForce": { "type": "FAK" },
        "triggerPrice": 0.35
      }
    ]
  }'
```

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](/api-reference/orders/get-order) and
[Cancel Order](/api-reference/orders/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](/order-lifecycle#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).

```bash theme={null}
# Stop-limit: when the bid falls to 0.35, rest a limit sell at 0.34.
curl -X POST https://api.parlayx.com/v1/orders \
  -H "x-api-key: $PARLAYX_API_KEY" \
  -H "Idempotency-Key: stop-limit-2026-06-24-001" \
  -H "Content-Type: application/json" \
  -d '{
    "marketOrders": [
      {
        "venue": "polymarket",
        "type": "stop_limit",
        "outcomeId": "713210...",
        "side": "sell",
        "shares": 100,
        "timeInForce": { "type": "GTC" },
        "triggerPrice": 0.35,
        "limitPrice": 0.34
      }
    ]
  }'
```

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.
