Polymarket Bot Tutorial · Chapter 10 of 32

Quick answer (updated 2026-10-25)

FOK (Fill or Kill) fills the whole order immediately or cancels all of it. FAK (Fill and Kill) fills whatever it can immediately and cancels the rest, but needs at least one match. GTC (Good Till Cancelled) rests on the book until it fills or you cancel it. GTD (Good Till Date) rests until an expiry time you set. FOK and FAK never rest on the book, so they are Polymarket's market-order types; GTC and GTD are limit orders and can be post-only. Every Polymarket order carries a price limit, so none of them can fill worse than the price you allow.

Polymarket's order book (the CLOB) accepts exactly four order types, sent in the orderType field: GTC, GTD, FOK and FAK. This chapter explains what each one does with an unfilled remainder, shows the same order filling four different ways on one order book, and gives working code for the official Python and TypeScript SDKs. Polymarkets.co.il is an independent guide, not Polymarket. Every rule below was checked on 25 October 2026 against Polymarket's developer documentation.

What this chapter answers

  • FOK vs FAK: the one difference that matters
  • What a FOK order and a FAK order are on Polymarket
  • What GTC and GTD mean, and the GTD expiry rule
  • All Polymarket order types and options in one table
  • How to place each type in Python and TypeScript
  • Which type a bot should use, and what the FOK and FAK errors mean

FOK vs FAK: the difference

Both types try to fill immediately against orders already on the book, and neither ever rests there. They differ only in what happens when the book cannot fill the full size at your price limit:

  • FOK, Fill or Kill: all or nothing. If the full size is not available right now, the whole order is rejected and nothing trades.
  • FAK, Fill and Kill: take what is there. The available part fills and the unfilled remainder is cancelled. If nothing at all can match, it is rejected too.

FAK behaves like what other venues call IOC (Immediate or Cancel). Polymarket's own SDKs use FAK as the default for market orders.

FOK (Fill or Kill)FAK (Fill and Kill)
Partial fillNeverYes, the rest is cancelled
Rests on the bookNoNo
When the book is too thinWhole order rejectedFills the available part
When nothing matchesRejectedRejected
Error text (docs, 25 Oct 2026)order couldn't be fully filled. FOK orders are fully filled or killed.no orders found to match with FAK order. FAK orders are partially filled or killed if no match is found.
Pays the taker feeYes, on fee-charging marketsYes, on fee-charging markets
Default in the SDKNoYes

What is a FOK order?

A Fill or Kill order must fill its entire size the moment it reaches the matching engine, at your price limit or better. If it cannot, the exchange kills it: no shares change hands and no order stays open. You either get exactly the position you asked for or no position at all.

Use FOK when a partial fill would be worse than no fill: an entry that only makes sense at full size, one leg of a pair you plan to hedge with a second order, or an exit where you need a clean, known position afterwards. The cost is that FOK gets rejected more often on thin books, so your code needs a plan for the rejection: re-check the price and retry smaller, switch to FAK, or skip.

What is a FAK order on Polymarket?

A Fill and Kill order takes every share it can get immediately at your price limit or better, then cancels whatever is left. You can end up with the full size, part of it, or (if nothing matched) a rejection. It never leaves a resting order behind.

Use FAK when some fill is better than none: buying into a fast market with a price ceiling, cutting inventory quickly, or a stop-loss exit. Because the result can be partial, always read how much actually filled before your bot takes its next step. The order response carries makingAmount, takingAmount and the tradeIDs of the fills; the authenticated user WebSocket reports each fill as a trade event.

GTC and GTD: orders that rest on the book

GTC (Good Till Cancelled) is the standard limit order. Whatever part does not match immediately rests on the book at your price until another trader fills it or you cancel it. There is no time limit. If your GTC price already crosses the book, the crossing part fills at once as a taker and the remainder rests.

GTD (Good Till Date) is a GTC with an expiry, given as a Unix timestamp in seconds. Two rules from Polymarket's docs trip people up:

  • A GTD order expires one minute before its stated expiration (a security threshold). For an effective life of N seconds, set expiration = now + 60 + N.
  • The expiration must be at least 3 minutes in the future, or the order is rejected with invalid expiration. The shortest effective GTD life is therefore about two minutes.

Only GTC and GTD can be sent as post-only (postOnly: true). A post-only order is rejected with invalid post-only order: order crosses book instead of trading as a taker, which guarantees you only ever add liquidity. That matters because makers pay no fee and earn rebates; see market making on Polymarket.

Polymarket order types at a glance

As of 25 October 2026 the CLOB has four order types and a handful of options. There are no stop, trailing or iceberg order types for prediction markets; those are built in your own code.

Type or optionRests on bookPartial fillUnfilled partTypical use
GTC limitYesYesRests until filled or cancelledQuoting, patient entries and take-profit exits
GTD limitYes, until expiryYesExpires 60 s before the set timeQuotes that must die before a known event
FOK marketNoNoWhole order rejectedAll-or-nothing entries
FAK marketNoYesCancelledTake available liquidity now, stop-loss exits
postOnly (GTC, GTD only)YesYesRejected if it would crossGuaranteed maker orders
Batch POST /orders1 to 15 signed orders per request; each one is accepted or rejected on its own
Order heartbeat POST /heartbeatsOptional dead man's switch: once enabled, if no heartbeat arrives for about 10 seconds the exchange queues a best-effort cancel of all open orders for that API key; send one every 5 seconds

Two market settings apply to every type. The price must sit on the market's tick size (0.01 on most markets; 0.1, 0.005, 0.0025, 0.001 and 0.0001 also exist), and the size must meet the market's minimum order size (min_order_size in the order book, often 5). Read both from the market rather than hardcoding them, and watch for tick_size_change on the market WebSocket.

One order, four outcomes: a worked example

Say the asks for an outcome are 25 shares at 0.52 and 30 shares at 0.54, and you want to buy 40 shares paying no more than 0.53:

Order typeWhat happensYou end up with
FOK, limit 0.53Only 25 shares are offered at 0.53 or lower, so the full 40 cannot fillNothing; the order is rejected
FAK, limit 0.53Takes the 25 shares at 0.52, cancels the other 1525 shares at 0.52, no open order
GTC at 0.53Takes the 25 shares at 0.52 as a taker, rests a bid for 15 at 0.5325 shares plus an open bid for 15
GTD at 0.53, one hourSame as GTC, but the 15-share bid expires after about an hour25 shares plus a bid that dies on schedule

Notice the fill price: the 25 shares fill at 0.52, not at your 0.53 limit. Polymarket's docs state that price improvement always goes to the taker. Your limit is a worst case, not the price you pay.

How to place FOK, FAK, GTC and GTD orders (Python and TypeScript)

The current official clients are the unified SDKs: polymarket-client 0.14.0 on PyPI (import polymarket) and @polymarket/client 0.14.0 on npm, both released 21 October 2026. In them, GTC and GTD go through the limit-order method (omit expiration for GTC), and FOK and FAK go through the market-order method. A market BUY is sized in dollars (amount), a market SELL in shares (shares), and max_price / min_price set the worst price you accept. The wallet is your Polymarket account wallet (shown in the profile menu on polymarket.com); see authentication and wallets.

Python (polymarket-client 0.14.0)

# pip install polymarket-client
import asyncio, os, time
from decimal import Decimal
from polymarket import AsyncSecureClient

async def main():
    async with await AsyncSecureClient.create(
        private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
        wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
    ) as client:
        market = await client.get_market(slug="your-market-slug")
        yes = market.outcomes.yes
        asset_id = yes.position_id if market.version == "v2" else yes.token_id

        # FOK: spend 10 USD now, all or nothing, never above 0.53
        fok = await client.place_market_order(
            asset_id=asset_id, side="BUY", amount="10",
            max_price=Decimal("0.53"), order_type="FOK",
        )
        # FAK: sell up to 20 shares now, never below 0.50, cancel the rest
        fak = await client.place_market_order(
            asset_id=asset_id, side="SELL", shares="20",
            min_price=Decimal("0.50"), order_type="FAK",
        )
        # GTC: rest a bid for 10 shares at 0.48 until filled or cancelled
        gtc = await client.place_limit_order(
            asset_id=asset_id, side="BUY", price="0.48", size="10",
        )
        # GTD: same bid with an effective life of one hour (expiry fires 60 s early)
        gtd = await client.place_limit_order(
            asset_id=asset_id, side="BUY", price="0.48", size="10",
            expiration=int(time.time()) + 60 + 3600,
        )
        for r in (fok, fak, gtc, gtd):
            if r.ok:
                print(r.order_id, r.status, r.trade_ids)
            else:
                print("rejected:", r.code, r.message)

asyncio.run(main())

TypeScript (@polymarket/client 0.14.0)

// npm install @polymarket/client@latest
import { createSecureClient, OrderSide, OrderType } from "@polymarket/client";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  wallet: process.env.POLYMARKET_WALLET_ADDRESS,
  signer: privateKey(process.env.POLYMARKET_PRIVATE_KEY),
});

const market = await client.fetchMarket({ slug: "your-market-slug" });
const { yes } = market.outcomes;
const assetId = market.version === "v2" ? yes.positionId : yes.tokenId;

const fok = await client.placeMarketOrder({
  assetId, side: OrderSide.BUY, amount: "10", maxPrice: 0.53, orderType: OrderType.FOK,
});
const fak = await client.placeMarketOrder({
  assetId, side: OrderSide.SELL, shares: "20", minPrice: 0.5, orderType: OrderType.FAK,
});
const gtc = await client.placeLimitOrder({
  assetId, side: OrderSide.BUY, price: "0.48", size: "10",
});
const gtd = await client.placeLimitOrder({
  assetId, side: OrderSide.BUY, price: "0.48", size: "10",
  expiration: Math.floor(Date.now() / 1000) + 60 + 3600,
});

for (const r of [fok, fak, gtc, gtd]) {
  console.log(r.ok ? `${r.orderId} ${r.status}` : `rejected: ${r.code} ${r.message}`);
}

To quote as a guaranteed maker, add post_only=True (Python) or postOnly: true (TypeScript) to a GTC or GTD call. Still on the deprecated py-clob-client-v2 or @polymarket/clob-client-v2? The same four values exist there as OrderType.GTC, GTD, FOK and FAK; the old V1 py-clob-client stopped working on 28 April 2026.

Raw REST: where the order type goes

Over the plain API, orderType sits next to the signed order in the POST /order body; it is not part of the EIP-712 data you sign. Market orders (FOK and FAK) must carry "expiration": "0"; GTD carries its Unix-seconds expiry. Signing and headers are covered in the CLOB API guide.

{
  "deferExec": false,
  "order": { "...": "signed order fields", "expiration": "0" },
  "orderType": "FOK",
  "owner": "<your CLOB API key>"
}

What the exchange sends back

An accepted order returns a status. Read it before assuming you have a position:

StatusMeaningSeen with
matchedFilled (fully, or partly for FAK and crossing GTC) against resting ordersAll four types
liveResting on the bookGTC, GTD
delayedAccepted but held for a matching delay; no fills yetMarkets with a taker or sports delay
unmatchedMarketable order placed on the book after its delay without a matchDelay markets

Some markets hold marketable orders briefly before matching: a short taker delay on crypto markets (150 ms since 4 September 2026, per Polymarket's changelog) and a longer delay on configured live sports markets. While an order is delayed it cannot be cancelled, and a delayed FOK or FAK reply has no fills yet, so follow it on the user WebSocket. Since 24 July 2026, successful FOK and FAK replies return tradeIDs rather than transaction hashes; the SDKs' wait_for_order_fill_settlement() / waitForOrderFillSettlement() waits for the on-chain hashes.

Which order type should a bot use?

  • All-or-nothing entry at a price cap: FOK. Handle the rejection (retry smaller, or skip).
  • Get in or out now and accept a partial: FAK with max_price or min_price. Read the filled amount before the next step.
  • Quote, wait for a better price, avoid the taker fee: GTC, sent post-only so it can never cross.
  • Quote that must not survive a known event (a game start, a data release): GTD with the expiry rule above.
  • Stop-loss: no native stop order exists, so your bot watches the price and sends a FAK sell with a min_price floor when the trigger hits. A GTC sell cannot wait as a stop: priced below the current bid it fills at once, and priced above it waits for a rise, not a fall.
  • Resting orders from a process that might crash: enable the order heartbeat so stale orders get cancelled; see bot risk controls.

Fees decide a lot here. Takers pay fee = shares x feeRate x price x (1 - price) on fee-charging markets (feeRate 0.07 on crypto, 0.05 on sports, 0.04 on politics, 0 on geopolitics, per the fee table on 25 October 2026); makers pay nothing and share in daily rebates. FOK and FAK always take, so they always pay the fee where one applies. The full table is in the CLOB API guide.

FOK and FAK error messages

  • order couldn't be fully filled. FOK orders are fully filled or killed. The book did not have your full size at your price. Nothing traded.
  • no orders found to match with FAK order. FAK orders are partially filled or killed if no match is found. Not a single share was available at your limit. Nothing traded.
  • FOK orders are filled or killed (HTTP 500): the same outcome reported by the matching engine.
  • invalid expiration: a GTD expiry in the past or less than 3 minutes ahead.
  • order {id} is invalid. Size ({size}) lower than the minimum: {min}: below the market's minimum order size.

Every other CLOB error, with fixes, is on the Polymarket API errors page.

Sources checked on 25 October 2026 (named, not linked): Polymarket docs pages Place Orders, Order Lifecycle, Post a New Order (CLOB OpenAPI), Error Codes, Market Details, Fees, Send Heartbeat and Matching Engine Restarts, and the Predictions changelog (all under docs.polymarket.com); package versions on PyPI and npm.

Frequently asked questions

What is the difference between FOK and FAK on Polymarket?
Both fill immediately against resting orders and never stay on the book. FOK (Fill or Kill) is all or nothing: if your full size is not available at your price limit, the whole order is rejected. FAK (Fill and Kill) fills whatever is available and cancels the rest; it is rejected only if nothing at all can match.
What is a FOK order?
A Fill or Kill order must fill its entire size at once, at your price limit or better, or it is cancelled with nothing traded. On Polymarket a failed FOK returns: order couldn't be fully filled. FOK orders are fully filled or killed.
What is a FAK order on Polymarket?
A Fill and Kill order takes every share available at your price limit right now and cancels the unfilled remainder, so you can get a full, partial or zero fill. It works like an IOC (Immediate or Cancel) order on other venues and is the default market-order type in Polymarket's SDKs.
What does GTC mean on Polymarket?
GTC is Good Till Cancelled: a limit order that rests on the order book at your price until another trader fills it or you cancel it. Any part that crosses the book when you place it fills at once, and the rest waits. GTC is the default orderType in the CLOB API.
What is a GTD order and how do I set the expiration?
GTD (Good Till Date) is a resting limit order with an expiry in Unix seconds. Polymarket expires it one minute before the stated time, so for an effective life of N seconds set expiration to now + 60 + N. The expiration must be at least 3 minutes in the future or the order is rejected with invalid expiration.
What order types does Polymarket support?
Four: GTC and GTD (limit orders that can rest on the book) and FOK and FAK (market orders that never rest). GTC and GTD can also be post-only, which rejects them instead of letting them trade as a taker. You can send up to 15 orders in one batch request. There is no native stop, trailing or iceberg order type for prediction markets.
Is a Polymarket market order FOK or FAK?
Either. A market order is a limit order priced to execute immediately, and you choose FOK or FAK in orderType. The official SDKs default to FAK. Set max_price on a buy or min_price on a sell so the order cannot fill beyond the price you accept.
Can a FOK or FAK order be post-only?
No. Polymarket's API supports postOnly only for GTC and GTD orders. FOK and FAK exist to take liquidity immediately, so they always trade as the taker and pay the taker fee on markets that charge one.
Does Polymarket support stop-loss orders?
Not for prediction markets. The CLOB order types are GTC, GTD, FOK and FAK, so a stop-loss runs in your own code: watch the price and, when your trigger hits, send a FAK sell with a minimum price. A GTC sell cannot act as a stop: priced below the current bid it fills at once, and priced above it waits for a rise, not a fall.
What is the minimum order size on Polymarket?
Each market sets its own minimum, returned as min_order_size in the order book (often 5), and its own tick size (usually 0.01). Orders below the minimum fail with Size lower than the minimum, and prices off the tick grid are rejected. Read both values from the market instead of hardcoding them.
Why did my Polymarket FOK order fail?
The book did not hold your full size at or better than your price limit at that moment, so the whole order was killed and nothing traded. Retry with a smaller size or a wider limit, switch to FAK if a partial fill is acceptable, or post a GTC limit order and wait for a seller.