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

# Order Lifecycle

> Submit an order, poll its status, and cancel — end to end

ParlayX routes a single order across one or more prediction-market venues
and reports progress through a unified `Order` resource. This guide walks
through the full lifecycle: submit an order, poll for status, interpret the
fields that appear as it executes, and cancel if needed.

## Prerequisites

* A funded ParlayX account. See [Deposit](/deposit).
* A ParlayX API key.
* A market to trade, identified by its `venue` and the `outcomeId` of the side
  you want. There are two ways to get the `outcomeId`:

  * [Search Markets](/api-reference/markets/search-markets) returns matching
    markets with their `venue` and `marketId` — but **not** outcomes. Pass the
    `marketId` to [Get Market](/api-reference/markets/get-market) to read the
    market's outcomes, each with its `outcomeId`.
  * [Find Market Matches](/api-reference/markets/find-market-matches) returns the
    outcomes (with `outcomeId`) directly, for a market matched across venues.

  Limitless orders also carry the `marketId`, exactly as discovery returns it.

## 1. Submit an order

Submit one or more orders with
[POST /v1/orders](/api-reference/orders/submit-order). The response returns
an aggregator-issued `orderId` — keep it; it is the only handle you need
for everything that follows.

```bash theme={null}
curl -X POST https://api.parlayx.com/v1/orders \
  -H "x-api-key: $PARLAYX_API_KEY" \
  -H "Idempotency-Key: order-2026-06-07-001" \
  -H "Content-Type: application/json" \
  -d '{
    "marketOrders": [
      {
        "venue": "polymarket",
        "type": "market",
        "outcomeId": "713210...",
        "side": "buy",
        "amount": 100,
        "timeInForce": { "type": "FOK" }
      }
    ]
  }'
```

Each entry in `marketOrders` is a single venue order. `venue`, `type`
(`"market"`, `"limit"`, `"stop"`, or `"stop_limit"`), `outcomeId`, `side`,
`amount` (in USDC), and `timeInForce` are required; Limitless orders also carry
the `marketId` from the lookup. `timeInForce` is an object tagged by `type` (e.g.
`{ "type": "FOK" }`); a `"GTD"` order carries its `expiresAt` inside it. A
`"limit"` order additionally requires a `limitPrice`; a `"stop"` order requires
a `triggerPrice` and fires a market child when the price crosses it; a
`"stop_limit"` requires both a `triggerPrice` and a child `limitPrice` and fires
a resting limit child (see
[Stop orders](/pricing-and-execution#stop-orders-conditional)). See
[Pricing and Execution](/pricing-and-execution) for the per-venue order
shapes and price guards.

The `marketOrders` array can mix order types freely — a single submit can carry,
say, a market buy, a resting limit, and a stop together. They share one `orderId`
and are read and cancelled as one order.

<Note>
  Each order must be worth at least **\$1** in notional. For an `amount`-sized
  order that is the `amount` itself; for an order sized in `shares` with a
  `limitPrice`, it is `shares × limitPrice`. Orders below the minimum are
  rejected at submission with a `400`, so an undersized order fails fast
  instead of resting unfilled.
</Note>

The `Idempotency-Key` header is **required**: re-submitting the same key
with the same body returns the original `orderId` instead of placing a
duplicate order (safe to retry on network errors), while reusing it with a
different body is rejected with `422`. Use a stable, unique value per
logical order.

```json theme={null}
{
  "orderId": "3f8b2c9a-2d18-4f7e-9c2a-1b6e1f0c8a4d"
}
```

Submission is asynchronous. A successful response means ParlayX accepted
the order; it does not mean the order has rested or filled yet.

## 2. Poll the order

Fetch the latest state with
[GET /v1/orders/{orderId}](/api-reference/orders/get-order), passing the
`orderId` as a path parameter.

```bash theme={null}
curl "https://api.parlayx.com/v1/orders/3f8b2c9a-2d18-4f7e-9c2a-1b6e1f0c8a4d" \
  -H "x-api-key: $PARLAYX_API_KEY"
```

```json theme={null}
{
  "orderId": "3f8b2c9a-2d18-4f7e-9c2a-1b6e1f0c8a4d",
  "status": "partial",
  "filledAmount": 60,
  "executionCost": 0.42,
  "marketOrders": [
    {
      "type": "market",
      "marketInfo": {
        "venue": "polymarket",
        "outcomeId": "713210..."
      },
      "status": "filled",
      "filledAmount": 40,
      "averagePrice": 0.62,
      "executionCost": 0.18,
      "error": null
    },
    {
      "type": "market",
      "marketInfo": {
        "venue": "limitless",
        "marketId": "will-it-rain-in-nyc",
        "outcomeId": "0xabc..."
      },
      "status": "partial",
      "filledAmount": 20,
      "averagePrice": 0.61,
      "executionCost": 0.09,
      "error": null
    }
  ],
  "createdAt": "2026-06-01T12:00:00.000Z",
  "updatedAt": "2026-06-01T12:00:03.412Z"
}
```

Poll until `status` is one of the terminal states (`filled`, `cancelled`,
or `failed`). A modest polling interval — for example, every one to two
seconds — is usually enough; `updatedAt` advances whenever fills or status
transitions occur.

## 3. Interpret the lifecycle

Every order moves through a curated six-state lifecycle. The same
`status` enum is reported at the order level and on each market order.

| Status      | Meaning                                                                          | Terminal |
| ----------- | -------------------------------------------------------------------------------- | -------- |
| `pending`   | Accepted by ParlayX; funding and signing in progress. Not yet resting on a book. | No       |
| `open`      | Resting on the venue's book with no fills yet.                                   | No       |
| `partial`   | Some size has filled; the remainder is still working.                            | No       |
| `filled`    | The full size has filled.                                                        | Yes      |
| `cancelled` | Cancelled before it could fully fill.                                            | Yes      |
| `failed`    | The order could not be executed. Check `error` on the failing market order.      | Yes      |

The order-level `status` is a roll-up of its market orders. Multi-venue
orders commonly show `partial` while individual market orders are still
moving between `open`, `partial`, and `filled`.

## 4. Read the result

The `Order` itself is type-agnostic — a container for one or more market
orders, mirroring the way you submit them. It carries the data you need to
settle and reconcile:

* `filledAmount` — Total amount filled across all market orders, in USDC.
* `executionCost` — All-in cost to execute the order, in USDC: venue fees
  plus collateral conversion slippage. Gas is excluded — ParlayX covers
  it — and any recoverable leftover collateral is also excluded.
* `marketOrders[]` — The execution result for each market order you
  submitted, in the order submitted (mirroring the submit request's
  `marketOrders`). Each entry carries its own `type` (`market`, `limit`, `stop`,
  or `stop_limit` — the same discriminator you submitted): switch on it to know which
  fields the entry carries. Each entry echoes the `marketInfo` you submitted —
  `venue` and `outcomeId`, plus `marketId` on Limitless entries (Polymarket
  entries never carry one) — so you can match a result back to the market it
  traded without relying on array order. Each entry also reports its own
  `status`, `filledAmount`, `averagePrice` (as an implied probability
  between 0 and 1, `null` until it has a fill), `executionCost`, and
  `error`. A `stop` or `stop_limit` entry adds one conditional field
  (`conditionalStatus`), described in [Conditional orders](#conditional-orders)
  below.
* `createdAt` / `updatedAt` — ISO-8601 timestamps. `updatedAt` advances
  with every state or fill change.

<Note>
  `executionCost` replaces the previous `fees` field on both the order and
  each market order. Order-level `executionCost` includes venue fees plus
  collateral conversion slippage; per-market-order `executionCost` is the
  venue fees charged on that market order only.
</Note>

### Conditional orders

A conditional order (`stop` / `stop_limit`) can stand alone or be batched with
other market orders; either way each conditional is its own `marketOrders` entry
of that `type`. A conditional is **one order end to end** — the same `orderId`
you got at submit is the only handle you ever need, even after it fires. The
entry carries one field a `market` or `limit` entry does not:

* `conditionalStatus` — the conditional's own lifecycle: `armed` (watching,
  nothing resting), `triggered` (the level crossed and the fire is claimed),
  `fired` (it has placed its order), or the terminal `cancelled`, `expired`, and
  `failed`.

While `armed`/`triggered`, the entry rests nothing, so `status` reads `open` and
`filledAmount` is `0`. Once `fired`, the order it places is rolled up onto this
same entry: `status`, `filledAmount`, `averagePrice`, and `executionCost` track
the placed order's real execution — `open` then `partial` then `filled` (a
`stop_limit`'s resting limit can sit `open`/`partial` for a while before it
fills, or never if the market gapped past the limit). There is no second order
id to fetch; just keep reading the conditional's `orderId`.

```json theme={null}
{
  "orderId": "5550a73f-...",
  "status": "partial",
  "filledAmount": 1.96,
  "executionCost": 0.01,
  "marketOrders": [
    {
      "type": "stop_limit",
      "marketInfo": {
        "venue": "polymarket",
        "outcomeId": "713210..."
      },
      "status": "partial",
      "filledAmount": 1.96,
      "averagePrice": 0.49,
      "executionCost": 0.01,
      "error": null,
      "conditionalStatus": "fired"
    }
  ],
  "createdAt": "2026-06-01T12:00:00.000Z",
  "updatedAt": "2026-06-01T12:00:05.000Z"
}
```

### Failure reasons

When a market order ends in `failed`, its `error` field is an object with a
machine-readable `code` from a fixed vocabulary and a human-readable
`message`. Use the `code` to decide whether to retry, adjust, or surface
the error to the user. `error` is `null` whenever the market order is not in
the `failed` state.

| `error.code`         | What it means                                                       |
| -------------------- | ------------------------------------------------------------------- |
| `INSUFFICIENT_FUNDS` | Not enough balance to fund the market order.                        |
| `PRICE_EXCEEDED`     | Fills would have breached the price bound you specified.            |
| `NOT_EXECUTABLE`     | The order could not be routed or sized on this venue.               |
| `VENUE_REJECTED`     | The venue declined the order.                                       |
| `INTERNAL_ERROR`     | An internal failure. Safe to retry; contact support if it persists. |

## 5. Cancel an order

To stop a working order before it fully fills, call
[DELETE /v1/orders/{orderId}](/api-reference/orders/cancel-order),
passing the `orderId` as a path parameter. The response is the same `Order`
resource, reflecting the post-cancel state.

```bash theme={null}
curl -X DELETE https://api.parlayx.com/v1/orders/3f8b2c9a-2d18-4f7e-9c2a-1b6e1f0c8a4d \
  -H "x-api-key: $PARLAYX_API_KEY"
```

A few things to know:

* Cancellation is best-effort. Any size that fills before the cancel
  reaches the venue is still reported in `filledAmount`, and the terminal
  `status` may end up as `partial` rolling into `cancelled`, or as
  `filled` if the order completed in the race.
* Orders that are already terminal (`filled`, `cancelled`, or `failed`)
  cannot be cancelled.
* After requesting a cancel, keep polling `GET /v1/orders/{orderId}` until
  `status` is terminal to confirm the final outcome.
