All orders on Polymarket are expressed as **limit orders**. Market orders are supported by submitting a limit order with a marketable price — your order executes immediately at the best available price on the book.
The underlying order primitive is structured, hashed, and signed using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) standard, then executed onchain via the Exchange contract. Preparing orders manually is involved, so we recommend using the open-source [TypeScript](https://github.com/Polymarket/clob-client) or [Python](https://github.com/Polymarket/py-clob-client) SDK clients, which handle signing and submission for you.
<Info>
If you prefer to use the REST API directly, you'll need to manage order
signing yourself. See [Authentication](/api-reference/authentication) for details on
| **GTC** (Good-Til-Cancelled) | Rests on the book until filled or cancelled | Default for passive limit orders |
| **GTD** (Good-Til-Date) | Active until a specified expiration time (UTC seconds timestamp), unless filled or cancelled first | Auto-expire orders before known events |
| **FOK** (Fill-Or-Kill) | Must be filled immediately and entirely, or the whole order is cancelled | All-or-nothing execution |
| **FAK** (Fill-And-Kill) | Fills as many shares as available immediately, then cancels any unfilled remainder | Partial immediate execution |
* **FOK** and **FAK** are market order types — they execute against resting liquidity immediately.
* **BUY**: specify the dollar amount you want to spend
* **SELL**: specify the number of shares you want to sell
* **GTC** and **GTD** are limit order types — they rest on the book at your specified price.
<Note>
**GTD expiration**: There is a security threshold of one minute. If you need
the order to expire in 90 seconds, the correct expiration value is `now + 1
minute + 30 seconds`.
</Note>
### Post-Only Orders
Post-only orders are limit orders that will only rest on the book and not match immediately on entry.
* If a post-only order would cross the spread (i.e., it is marketable), it will be **rejected** rather than executed.
* Post-only **cannot** be combined with market order types (FOK or FAK). If `postOnly = true` is sent with a market order type, the order will be rejected.
* Post-only can only be used with **GTC** and **GTD** order types.
***
## Tick Sizes
Markets have different minimum price increments (tick sizes). Your order price must conform to the market's tick size, or the order will be rejected.
You can also check the `minimum_tick_size` field on a market object returned
by the [Markets API](/market-data/fetching-markets).
</Tip>
***
## Negative Risk
Multi-outcome events (e.g., "Who will win the election?" with 3+ candidates) use a different exchange contract called the **Neg Risk CTF Exchange**. When placing orders on these markets, you must pass `negRisk: true` in the order options.
<CodeGroup>
```typescript TypeScript theme={null}
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for multi-outcome markets
},
);
```
```python Python theme={null}
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options={
"tick_size": "0.01",
"neg_risk": True, # Required for multi-outcome markets
}
)
```
</CodeGroup>
You can check whether a market uses negative risk via the SDK or the market object's `neg_risk` field:
There are also limits on order placement per market. You can only place orders that sum to less than or equal to your available balance for each market. For example, if you have 500 USDC.e in your funding wallet, you can place one order to buy 1000 YES at \$0.50 — but any additional buy orders in that market will be rejected since your entire balance is reserved for the first order.
The heartbeat endpoint maintains session liveness for order safety. If a valid heartbeat is not received within **10 seconds** (with up to a 5-second buffer), **all of your open orders will be cancelled**.
* On each request, include the most recent `heartbeat_id` you received. For your first request, use an empty string.
* If you send an invalid or expired `heartbeat_id`, the server responds with a `400 Bad Request` and provides the correct `heartbeat_id` in the response. Update your client and retry.
***
## Order Scoring
Check if your resting orders are eligible for [maker rebates](/market-makers/maker-rebates) scoring:
| `orderHash` | Unique hash for the filled order |
| `maker` | The user who generated the order and source of funds |
| `taker` | The user filling the order, or the Exchange contract if multiple limit orders are filled |
| `makerAssetId` | ID of the asset given out. If `0`, the order is a **BUY** (giving USDC.e for outcome tokens) |
| `takerAssetId` | ID of the asset received. If `0`, the order is a **SELL** (receiving USDC.e for outcome tokens) |
| `makerAmountFilled` | Amount of the asset given out |
| `takerAmountFilled` | Amount of the asset received |
| `fee` | Fees paid by the order maker |
***
## Error Messages
When placing an order, the response may include an `errorMsg` if the order could not be placed. If `success` is `false`, there was a server-side error:
| `matched` | Order placed and matched with a resting order |
| `live` | Order placed and resting on the book |
| `delayed` | Order is marketable but subject to a matching delay |
| `unmatched` | Order is marketable but failed to delay — placement still successful |
***
## Security
Polymarket's Exchange contract has been audited by Chainsecurity ([View Audit](https://github.com/Polymarket/ctf-exchange/blob/main/audit/ChainSecurity_Polymarket_Exchange_audit.pdf)).
The operator's privileges are limited to order matching and ensuring correct ordering. Operators cannot set prices or execute unauthorized trades. Users can cancel orders onchain independently if trust issues arise.