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

# Polymarket

> Sizing, pricing and order reads on Polymarket.

Polymarket is a wallet venue. Orders are placed from the pod wallet, and an
outcome is addressed by its `tokenId`. The order and read surface is in the
[Polymarket reference](/api-reference/polymarket/submit-order), and
`@parlayx/sdk` and Python `parlayx` expose it through `client.polymarket`.

## Sizing and pricing

A market BUY uses `amount` in dollars. `amount` caps the dollars spent and says
nothing about the price paid per share. `maxFillPrice` optionally sets the
highest price paid for each share.

A limit order uses `size` in outcome shares and `price`. A market SELL uses
`amount` in outcome shares.

`maxFillPrice` sets a BUY's per-share ceiling and `minFillPrice` sets a SELL's
per-share floor. Both take a price strictly between 0 and 1 and apply to `FOK`
and `FAK`. A SELL without `minFillPrice` is not unbounded: it uses a default
derived from the market's midpoint.

> [!NOTE]
>
> A bound can leave an order unfilled. Under `FAK` the order fills what it can
> within the bound and cancels the rest; under `FOK` it does not fill at all.

Polymarket quantizes sizes to its own grid and sets its own minimum. A size the
venue cannot execute is rejected rather than rounded down silently.

| Rule | Value |
| - | - |
| Share size precision | 2 decimal places |
| Minimum order size | Set per market by the venue (5 shares on the markets we see) |
| Price precision | The market's tick size |

A share-denominated size finer than 2 decimal places is rejected, and the error
names the size that does execute. That covers the shares on a SELL and the size
on a limit order of either side. A market BUY sized in dollars is unaffected.

> [!WARNING]
>
> **Closing a position can leave a residue, and the residue cannot be sold.**
> Selling 14.28 of a 14.285713-share position leaves 0.005713 shares behind.
> That remainder sits under the venue's minimum order size, so no further sell
> order can clear it.
>
> It is not lost. It redeems with the rest of the position once the market
> resolves. Treat a sub-share leftover as awaiting resolution, not as a failed
> close.

## Execution policy

A limit order can carry an expiry with
`timeInForce: { "type": "GTD", "expiresAt": "..." }`. Set `expiresAt` to an ISO
8601 timestamp at least 3 minutes and at most 30 days ahead. The timestamp you
send is passed through unchanged.

> [!WARNING]
>
> Polymarket expires a GTD order shortly before `expiresAt`, typically about a
> minute early. Allow for that when choosing how long a quote should rest.

## Reading orders and fills

A 201 means the order was accepted. On the response that placed the order, `status`
is the state Polymarket acknowledged, and three fields report the match it stated at
that moment. No later read answers this question: an order read reports the fills
accumulated since, so it cannot tell you what the placing call itself crossed.

| Field | What it is |
| - | - |
| `filledShares` | Outcome shares the venue reported matched |
| `filledAmountUsd` | Gross dollars for those shares, spent on a buy or received on a sell, before fees |
| `averagePrice` | `filledAmountUsd` divided by `filledShares`, to 6 decimal places |

Polymarket states each side of the trade, so `filledShares` and `filledAmountUsd`
are its own figures passed through unchanged. `averagePrice` is derived from them
and rounded, so the three do not multiply back together:

```
filledShares      120000
averagePrice      0.410005
filledAmountUsd   49200.55     <- the amount the venue stated
shares x price    49200.60     <- five cents higher, from the rounding
```

> [!WARNING]
>
> These fields describe the match reported at submission and do not confirm
> settlement. All three are null when the summary is unavailable, including on
> idempotent replays; null does not mean zero fills. Use `filledAmountUsd` for the
> reported amount because `averagePrice` is rounded. Use confirmed fills for final
> accounting.

A summary is unavailable in three situations: the order rested without crossing,
you retried under an idempotency key that already exists, or the acknowledgement
did not carry the figures. A retry placed nothing and returns the stored order, so
read the order back for what that order has filled since.

### Batch submit

`POST /v1/polymarket/orders/batch` takes `{ "orders": [...] }`, each element an
order in the same shape as `POST /v1/polymarket/orders`, under one
`Idempotency-Key` header for the whole batch. Re-send the identical batch under
the same key to retry it. It answers with `orders`, one element per request entry
in request order: `orders[i]` is the answer for the order you sent at position
`i`. An order has no id of your own yet, so position is the only way to match an
entry to its input.

* `success: true`: the entry was accepted, not confirmed at the venue, and a
  success is not a fill. `orderId` and `status` are set, `error` is null, and the
  fill fields report as on a single submit. For a new order `status` comes before
  the venue's acknowledgement. A replayed entry reports the order's current state,
  so it can read `PENDING`, `OPEN` or a terminal status, and a pending success is
  still not venue confirmation or a fill.
* `success: false`: `error` says why, and `status` and the fill fields are null.
  Read `error.code` before treating the entry as not placed:
  * `ORDER_RECONCILIATION_REQUIRED`: the outcome is unknown and the order may be live, so this is not proof nothing was placed. Read it back by the entry's `orderId`.
  * `INTERNAL_ERROR` with a null `orderId`: the outcome is unknown, so this is not proof nothing was placed either. Re-send the identical batch under the same `Idempotency-Key`.
  * Any other code: the entry was refused and not placed.

The key covers the whole request, including entries refused as invalid, so the
same key with any different batch is refused with `422 IDEMPOTENCY_CONFLICT`.
To fix a refused entry, send only the corrected order as a new batch under a new
key: re-sending the whole batch under a new key places its accepted orders again.

```json theme={null}
{
  "orders": [
    {
      "success": true,
      "orderId": "3f8b2c9a-2d18-4f7e-9c2a-1b6e1f0c8a4d",
      "status": "OPEN",
      "filledShares": null,
      "filledAmountUsd": null,
      "averagePrice": null,
      "error": null
    },
    {
      "success": false,
      "orderId": null,
      "status": null,
      "filledShares": null,
      "filledAmountUsd": null,
      "averagePrice": null,
      "error": { "code": "INVALID_REQUEST", "message": "Invalid batch order entry" }
    }
  ]
}
```

### Reading an order back

An expired order reports `status: "CANCELLED"` with
`cancellationReason: "EXPIRED"` and `error: null`. An order you cancelled
yourself reports `cancellationReason: null`.

Two reads settle late. An expired order can still read `OPEN` for a few minutes
after it has left the venue's book while final fills are confirmed, so that
status alone does not mean the order is still resting. And `FILLED` can appear
before the order read's own `filledShares` and `averagePrice` and its fills list
are populated. Those are the order's accumulated totals and are a different
question from the submit response's match summary, which describes one call.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.