Welcome to API Academy
Module 05 · API basics · ~25 min
Orders.
By the end of this module, your bot can actually place trades, open positions when its signal fires, scale them however your risk model dictates, and pull them back the moment the market turns. The point on the curriculum where it stops being a reader and starts being a trader.
To get there, you’ll place, size, and cancel real orders on Limitless, limit orders that rest on the book, FOK orders that cross it immediately, and the three cancel paths every bot needs when the market moves. Every trade your bot ever makes will flow through these endpoints.
API basics tier · Reference cardHow do you place an order via the Limitless API?
Through the SDK’s OrderClient.createOrder(), which wraps POST /orders: it signs an EIP-712 payload with your wallet, attaches your API key, and submits the order. You need both LIMITLESS_API_KEY and PRIVATE_KEY set, plus the market slug, outcome token id, side, price, and size. Three order types cover everything: GTC (Good-Til-Cancelled) rests on the book at your price, FAK (Fill-And-Kill) matches immediately available liquidity and cancels the remainder, and FOK (Fill-Or-Kill) crosses the book for a fixed makerAmount of USDC, filling entirely or rejecting. The response carries an orderId and a settlementStatus (UNMATCHED is expected for a resting limit). Attach a clientOrderId so retries are idempotent, duplicates return 409 Conflict instead of a second fill, and remember the ack means “received,” not “filled.”
Order endpoints verified 2026-06-09 against the OpenAPI spec.
Section 01
Order types.
Two primitives: limit orders sit on the book at a price you choose, market orders cross the book immediately. Pick based on whether you care more about price or fill.
Limit orders
Post an order at a specific price and wait for a counterparty to cross it. You control the price; the exchange cannot fill you worse. You don’t control whether (or when) you fill.
- Price certainty
- Earns maker rebates when resting
- Use for passive fills and market making
- No fill guarantee
Market orders
Take the best available price on the book, whatever it is. You control the fill; the exchange controls the price. On a thin book, slippage can hurt.
- Fill certainty (if depth exists)
- Use when you need to get out fast
- Use when crossing a signal
- Always pass a max-slippage guard
Section 02
Placing a limit order.
The SDK’s OrderClient wraps POST /orders. Under the hood it signs an EIP-712 payload with your wallet, attaches your API key, and submits it. You pass the market slug, outcome token id, side, price, and size; the SDK handles the signing and submits a GTC order.
How to run this
- Set both LIMITLESS_API_KEY and PRIVATE_KEY in your environment. Swap btc-100k-weekly for a real market slug and pick a price that won’t cross the book immediately.
- Save as place-limit.ts, then run npx tsx place-limit.ts.
- Save as place_limit.py, then run python place_limit.py.
- Save as main.go inside a Go module, then run go run main.go.
- You see an orderId and a settlementStatus printed, UNMATCHED is expected for a resting limit. Your order is live on the book.
// Module 05, Placing a Limit Order
// Buy 100 YES on a market at $0.42, good-til-cancelled.
import {
HttpClient,
MarketFetcher,
OrderClient,
Side,
OrderType,
} from '@limitless-exchange/sdk';
import { Wallet } from 'ethers';
const httpClient = new HttpClient({ apiKey: process.env.LIMITLESS_API_KEY });
const marketFetcher = new MarketFetcher(httpClient);
const wallet = new Wallet(process.env.PRIVATE_KEY!);
const orderClient = new OrderClient({ httpClient, wallet, marketFetcher });
async function placeLimit() {
const market = await marketFetcher.getMarket('btc-100k-weekly');
const result = await orderClient.createOrder({
marketSlug: market.slug,
tokenId: market.positionIds[0], // YES outcome token
side: Side.BUY,
price: 0.42, // USDC per share, 0.01–0.99
size: 100, // number of shares
orderType: OrderType.GTC, // rests until cancelled
});
console.log('orderId: ', result.order.id);
console.log('settlementStatus:', result.execution.settlementStatus);
// UNMATCHED | MATCHED | MINED | CONFIRMED | RETRYING | FAILED
}
placeLimit().catch(console.error);
# Module 05, Placing a Limit Order
# Buy 100 YES on a market at $0.42, good-til-cancelled.
import asyncio
import os
from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.orders import OrderClient
from limitless_sdk.types import Side, OrderType
http_client = HttpClient() # auto-loads LIMITLESS_API_KEY
async def place_limit() -> None:
market_fetcher = MarketFetcher(http_client)
wallet = Account.from_key(os.environ["PRIVATE_KEY"])
order_client = OrderClient(
http_client,
wallet=wallet,
market_fetcher=market_fetcher,
)
market = await market_fetcher.get_market("btc-100k-weekly")
result = await order_client.create_order(
token_id=market["positionIds"][0], # YES outcome token
price=0.42, # USDC per share, 0.01–0.99
size=100.0,
side=Side.BUY,
order_type=OrderType.GTC, # rests until cancelled
market_slug=market["slug"],
post_only=True, # guarantees maker fees
)
print("orderId: ", result["order"]["id"])
print("settlementStatus:", result["execution"]["settlementStatus"])
await http_client.close()
if __name__ == "__main__":
asyncio.run(place_limit())
// Module 05, Placing a Limit Order
// Buy 100 YES on a market at $0.42, good-til-cancelled.
package main
import (
"context"
"fmt"
"log"
"os"
limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"
)
func main() {
ctx := context.Background()
client := limitless.NewHttpClient()
marketFetcher := limitless.NewMarketFetcher(client)
orderClient, err := limitless.NewOrderClient(client, os.Getenv("PRIVATE_KEY"))
if err != nil {
log.Fatal(err)
}
market, err := marketFetcher.GetMarket(ctx, "btc-100k-weekly")
if err != nil {
log.Fatal(err)
}
result, err := orderClient.CreateOrder(ctx, limitless.CreateOrderParams{
OrderType: limitless.OrderTypeGTC,
MarketSlug: market.Slug,
Args: limitless.GTCOrderArgs{
TokenID: market.Tokens.Yes, // YES outcome token
Side: limitless.SideBuy,
Price: 0.42, // USDC per share, 0.01–0.99
Size: 100.0,
PostOnly: true, // guarantees maker fees
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("orderId: %s\n", result.Order.ID)
fmt.Printf("settlementStatus: %s\n", result.Execution.SettlementStatus)
}
Three order types: GTC, FAK, and FOK.
GTC (Good-Til-Cancelled) rests on the book at your price until it fills or you cancel. FAK (Fill-And-Kill) matches immediately available liquidity at your price/size and cancels any unmatched remainder, the partial-fill variant. FOK (Fill-Or-Kill) crosses the book immediately for a fixed makerAmount, it fills entirely or rejects.
Section 03
Placing a market order.
Limitless expresses “market” orders as OrderType.FOK, fill-or-kill. You commit a fixed makerAmount of USDC and the matching engine either fills the whole thing against the book or rejects the order entirely. No price, no slippage guessing, no partial fills.
// Module 05, Placing a Market Order (FOK)
// Spend $50 of USDC crossing the book for YES. Fill-or-kill.
import {
HttpClient,
MarketFetcher,
OrderClient,
Side,
OrderType,
} from '@limitless-exchange/sdk';
import { Wallet } from 'ethers';
import { randomUUID } from 'node:crypto';
const httpClient = new HttpClient({ apiKey: process.env.LIMITLESS_API_KEY });
const marketFetcher = new MarketFetcher(httpClient);
const wallet = new Wallet(process.env.PRIVATE_KEY!);
const orderClient = new OrderClient({ httpClient, wallet, marketFetcher });
async function placeMarket() {
const market = await marketFetcher.getMarket('btc-100k-weekly');
const result = await orderClient.createOrder({
marketSlug: market.slug,
tokenId: market.positionIds[0],
side: Side.BUY,
makerAmount: 50, // USDC budget, no price, no size
orderType: OrderType.FOK,
clientOrderId: randomUUID(), // idempotency, see Section 04
});
console.log('matched: ', result.execution.matched);
console.log('settlementStatus: ', result.execution.settlementStatus);
console.log('usdNet: ', result.execution.totalsRaw.usdNet);
console.log('txHash: ', result.execution.txHash);
}
placeMarket().catch(console.error);
# Module 05, Placing a Market Order (FOK)
# Spend $50 of USDC crossing the book for YES. Fill-or-kill.
import asyncio
import os
import uuid
from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.orders import OrderClient
from limitless_sdk.types import Side, OrderType
http_client = HttpClient()
async def place_market() -> None:
market_fetcher = MarketFetcher(http_client)
wallet = Account.from_key(os.environ["PRIVATE_KEY"])
order_client = OrderClient(
http_client,
wallet=wallet,
market_fetcher=market_fetcher,
)
market = await market_fetcher.get_market("btc-100k-weekly")
result = await order_client.create_order(
token_id=market["positionIds"][0],
maker_amount=50.0, # USDC budget, no price, no size
side=Side.BUY,
order_type=OrderType.FOK,
market_slug=market["slug"],
client_order_id=str(uuid.uuid4()), # idempotency, see Section 04
)
execution = result["execution"]
print("matched: ", execution["matched"])
print("settlementStatus: ", execution["settlementStatus"])
print("usdNet: ", execution["totalsRaw"]["usdNet"])
print("txHash: ", execution.get("txHash"))
await http_client.close()
if __name__ == "__main__":
asyncio.run(place_market())
// Module 05, Placing a Market Order (FOK)
// Spend $50 of USDC crossing the book for YES. Fill-or-kill.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/google/uuid"
limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"
)
func main() {
ctx := context.Background()
client := limitless.NewHttpClient()
marketFetcher := limitless.NewMarketFetcher(client)
orderClient, err := limitless.NewOrderClient(client, os.Getenv("PRIVATE_KEY"))
if err != nil {
log.Fatal(err)
}
market, err := marketFetcher.GetMarket(ctx, "btc-100k-weekly")
if err != nil {
log.Fatal(err)
}
result, err := orderClient.CreateOrder(ctx, limitless.CreateOrderParams{
OrderType: limitless.OrderTypeFOK,
MarketSlug: market.Slug,
ClientOrderID: uuid.NewString(), // idempotency, see Section 04
Args: limitless.FOKOrderArgs{
TokenID: market.Tokens.Yes,
Side: limitless.SideBuy,
MakerAmount: 50.0, // USDC budget
},
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("matched: %v\n", result.Execution.Matched)
fmt.Printf("settlementStatus: %s\n", result.Execution.SettlementStatus)
fmt.Printf("usdNet: %s\n", result.Execution.TotalsRaw.USDNet)
fmt.Printf("txHash: %s\n", result.Execution.TxHash)
}
How to run this
- Keep both env vars set. Check the orderbook first, FOK rejects partial fills, so pick a makerAmount the book can actually absorb.
- Save the snippet above as place-market.ts, then run npx tsx place-market.ts.
- Save the snippet above as place_market.py, then run python place_market.py.
- Save the snippet above as main.go inside a Go module, then run go run main.go.
- On success you see matched: true, a settlement status, the USDC usdNet, and a txHash you can look up on Base.
FOK is atomic, size the makerAmount deliberately.
Because FOK rejects partial fills, a too-large makerAmount on a thin book will keep bouncing back. Check GET /markets/{slug}/orderbook first, or start with a GTC limit that crosses and let it rest if it doesn’t fill.
Section 04
Cancelling orders.
Cancel a single order by id, cancel every order on a market in one shot, or batch-cancel a specific set with POST /orders/cancel-batch. For idempotent order creation, attach a clientOrderId to the original createOrder call, duplicates return 409 Conflict instead of double-submitting.
// Module 05, Cancelling Orders
// Cancel one by id, cancel all on a market, or batch-cancel a set.
import {
HttpClient,
MarketFetcher,
OrderClient,
} from '@limitless-exchange/sdk';
import { Wallet } from 'ethers';
const httpClient = new HttpClient({ apiKey: process.env.LIMITLESS_API_KEY });
const marketFetcher = new MarketFetcher(httpClient);
const wallet = new Wallet(process.env.PRIVATE_KEY!);
const orderClient = new OrderClient({ httpClient, wallet, marketFetcher });
async function cancelEverything(orderId: string, marketSlug: string) {
// 1. Cancel one order by id.
// DELETE /orders/{orderId}
await orderClient.cancel(orderId);
// 2. Cancel every live order on a single market.
// DELETE /orders/all/{slug}
await orderClient.cancelAll(marketSlug);
// 3. Batch-cancel a specific set (orders must all be from the same market).
// POST /orders/cancel-batch body: { orderIds: UUID[] }
await httpClient.post('/orders/cancel-batch', {
orderIds: [
'c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1',
'4a1e1c56-9a13-4e22-8e17-0b2f4c1d3e22',
],
});
}
cancelEverything('c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1', 'btc-100k-weekly')
.catch(console.error);
# Module 05, Cancelling Orders
# Cancel one by id, cancel all on a market, or batch-cancel a set.
import asyncio
import os
from eth_account import Account
from limitless_sdk.api import HttpClient
from limitless_sdk.markets import MarketFetcher
from limitless_sdk.orders import OrderClient
http_client = HttpClient()
async def cancel_everything(order_id: str, market_slug: str) -> None:
market_fetcher = MarketFetcher(http_client)
wallet = Account.from_key(os.environ["PRIVATE_KEY"])
order_client = OrderClient(
http_client,
wallet=wallet,
market_fetcher=market_fetcher,
)
# 1. Cancel one order by id.
# DELETE /orders/{order_id}
await order_client.cancel(order_id)
# 2. Cancel every live order on a single market.
# DELETE /orders/all/{slug}
await order_client.cancel_all(market_slug)
# 3. Batch-cancel a specific set (same-market only).
# POST /orders/cancel-batch body: { "orderIds": [UUID, ...] }
await http_client.post(
"/orders/cancel-batch",
json={
"orderIds": [
"c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1",
"4a1e1c56-9a13-4e22-8e17-0b2f4c1d3e22",
],
},
)
await http_client.close()
if __name__ == "__main__":
asyncio.run(cancel_everything(
"c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1",
"btc-100k-weekly",
))
// Module 05, Cancelling Orders
// Cancel one by id, cancel all on a market, or batch-cancel a set.
package main
import (
"context"
"fmt"
"log"
"os"
limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"
)
func main() {
ctx := context.Background()
client := limitless.NewHttpClient()
orderClient, err := limitless.NewOrderClient(client, os.Getenv("PRIVATE_KEY"))
if err != nil {
log.Fatal(err)
}
// 1. Cancel one order by id.
// DELETE /orders/{orderId}
if _, err := orderClient.Cancel(ctx, "c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1"); err != nil {
log.Fatal(err)
}
// 2. Cancel every live order on a single market.
// DELETE /orders/all/{slug}
if _, err := orderClient.CancelAll(ctx, "btc-100k-weekly"); err != nil {
log.Fatal(err)
}
// 3. Batch-cancel a specific set (same-market only).
// POST /orders/cancel-batch body: { "orderIds": [UUID, ...] }
body := map[string]any{
"orderIds": []string{
"c24c5aa4-8d8e-4e68-9fd3-d9e5e9e4b0a1",
"4a1e1c56-9a13-4e22-8e17-0b2f4c1d3e22",
},
}
if _, err := client.Post(ctx, "/orders/cancel-batch", body); err != nil {
log.Fatal(err)
}
fmt.Println("All cancel variants issued.")
}
How to run this
- Keep both env vars set. Replace the two example UUIDs with real orderId values from the limit order you placed in Section 02.
- Save the snippet above as cancel-orders.ts, then run npx tsx cancel-orders.ts.
- Save the snippet above as cancel_orders.py, then run python cancel_orders.py.
- Save the snippet above as main.go inside a Go module, then run go run main.go.
- No errors thrown. The REST API returns 2xx on each cancel and your order disappears from the book when you re-query positions.
Wire orders into your control panel.
The seed fills.ndjson you dropped in Module 02 was hand-written. As soon as your code from this module places a real order and a fill comes back, append a line with the same shape (ts, market, side, size_usd, price, order_id) to $ACADEMY_DATA_DIR/fills.ndjson. The recent-fills feed in your panel surfaces the new line on the next poll, the moment your order placement code stops being abstract and shows up on your phone.
Placing orders on Limitless: what people ask
Each answer also ships invisibly as schema.org FAQ data for search engines and AI assistants. Tap a question to expand.
-
What is the difference between GTC, FAK, and FOK orders?
GTC(Good-Til-Cancelled) rests on the book at your price until it fills or you cancel.FAK(Fill-And-Kill) matches immediately available liquidity at yourprice/sizeand cancels any unmatched remainder, the partial-fill variant.FOK(Fill-Or-Kill) crosses the book immediately for a fixedmakerAmountof USDC: it fills entirely or rejects. GTC and FAK takeprice/size; FOK takesmakerAmount. -
How do you place a market order on Limitless?
Limitless expresses market orders asOrderType.FOK: you commit a fixedmakerAmountof USDC and the matching engine fills the whole thing against the book or rejects the order entirely. No price, no slippage guessing, no partial fills. Because FOK is atomic, a too-largemakerAmounton a thin book keeps bouncing back, so checkGET /markets/{slug}/orderbookfirst, or start with a GTC limit that crosses and let it rest if it doesn’t fill. -
How do you cancel orders via the Limitless API?
Three paths. Cancel one by id withDELETE /orders/{orderId}(orderClient.cancel). Cancel every live order on a single market withDELETE /orders/all/{slug}(cancelAll). Batch-cancel a specific set withPOST /orders/cancel-batchand a body oforderIds; the batch must all be from the same market. Your bot needs all three for the moment a signal flips or the book moves against it. -
Does an order acknowledgment mean the order filled?
No, they’re different events.placeOrderresolves with atxHashthe moment the exchange accepts the order; a resting limit comes backUNMATCHED, and the matching engine can still bounce an order inside the spread. Move position state on fill events only: subscribe to order events, or pollPOST /orders/status/batchwith the order id until it shows filled. -
How do you make order placement idempotent?
Attach aclientOrderId(a UUID) to the originalcreateOrdercall. If a retry resubmits the same order, the API returns409 Conflictinstead of double-submitting, so a network blip can’t turn one intended position into two. The module’s market-order example generates one withrandomUUID(); treat it as mandatory on anything that crosses the book.
Section 05
Module checklist.
Tick each item once you’ve actually done it. The Continue button unlocks at 5/5.
I can explain when to use a limit order vs a market order in my own words
I placed a limit order via the SDK and saw it appear on the book
I understand how GTC, FAK, and FOK differ, GTC/FAK take price/size while FOK takes makerAmount
I check orderbook depth before sending FOK, and I pass a clientOrderId for idempotency
I can cancel a single order, cancel all orders on a market, and batch-cancel via POST /orders/cancel-batch
Module 05 complete
Orders flowing.
Your bot is now a trader, not just an observer. It can open a position when a signal fires, size it however your risk model dictates, and unwind it the moment the trade stops working, without you watching the book.
Concretely, you can place orders on Limitless and pull them back when the market moves. Three things you walk away with:
A working OrderClient that signs EIP-712 orders for you, resting limits (GTC), market orders (FOK), and partial-fill crosses (FAK).
A clientOrderId pattern for idempotent submission, retries can’t double-spend, and duplicates return 409 Conflict instead of a second fill.
Three cancel paths, single by id, all-on-a-market, or a specific batch, so you can unwind fast when a signal flips or the book moves against you.
Next up: tracking what your bot actually holds. Module 06 covers positions, fills, and the PnL math that turns a stream of orders into a live P&L number you can stake decisions on.
Complete the checklist above to unlock