Skip to main content
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.
  • 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 returns matching markets with their venue and marketId — but not outcomes. Pass the marketId to Get Market to read the market’s outcomes, each with its outcomeId.
    • 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. The response returns an aggregator-issued orderId — keep it; it is the only handle you need for everything that follows.
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). See 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.
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.
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.
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/, passing the orderId as a path parameter.
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. 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 below.
  • createdAt / updatedAt — ISO-8601 timestamps. updatedAt advances with every state or fill change.
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.

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.

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.

5. Cancel an order

To stop a working order before it fully fills, call DELETE /v1/orders/, passing the orderId as a path parameter. The response is the same Order resource, reflecting the post-cancel state.
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.