Limit Orders
Place, monitor, and cancel venue-specific limit orders through the Execution API
Limit orders require a signed-in user session and live execution mode. Start with Authentication and Funding & Withdrawals before placing live orders.
Use limit orders when your app needs explicit price control on a single venue. AGG reserves the user's funds or shares, submits the order asynchronously, and reconciles fills, cancels, and terminal venue statuses back into the user's execution orders.
For marketable "buy the best available route" trades, use smart routing and
executeManaged instead. Limit orders are venue-specific:
you choose one venue, one venueMarketOutcomeId, a side, a limit price, and a size.
How It Works
The request uses user-tier auth: x-app-id plus the user's bearer token.
Use discovery, market pages, or orderbook APIs to select the exact venueMarketOutcomeId
for the venue where the order should rest.
For buys, the user needs enough spendable cash on AGG-managed balances. For sells, the user needs enough available position size in that outcome. AGG reserves the required amount while the order is open.
Call POST /execution/limit-orders. The response is usually pending first because the
executor submits to the venue asynchronously.
Use GET /execution/orders to read order state. If your app uses AGG WebSocket lifecycle
notifications, use the REST call as a backfill on page load and reconnect.
Call POST /execution/orders/{orderId}/cancel for queued or open orders. Cancels can return
cancel_pending before the venue confirms cancellation.
Request Shape
limitPriceRaw and sizeRaw are six-decimal integer strings:
| Field | Meaning | Example |
|---|---|---|
limitPriceRaw | Price in USDC-style six decimals. 200000 means $0.20. | "200000" |
sizeRaw | Contract/share size in six decimals. 5000000 means 5. | "5000000" |
timeInForce | Venue-supported duration or execution instruction. | "GTC" |
clientOrderId | Optional partner correlation key for this user. | "checkout-123-order-1" |
Prices must be greater than 0 and less than 1000000. A price of 1000000
would be $1.00, which is outside the accepted limit-order price range.
clientOrderId must be unique per user. Reusing it for the same user returns a conflict.
Place An Order
The SDK currently exposes this endpoint through client.request. Define a small typed wrapper in
your app so the rest of your code does not hand-build the REST call.
import { createAggClient } from "@agg-build/sdk";
type Venue =
| "polymarket"
| "limitless"
| "predict"
| "hyperliquid"
| "myriad";
type LimitOrderTimeInForce = "GTC" | "GTD" | "FOK" | "FAK" | "IOC" | "ALO";
type LimitOrderRequest = {
venue: Venue;
venueMarketOutcomeId: string;
side: "buy" | "sell";
limitPriceRaw: string;
sizeRaw: string;
timeInForce: LimitOrderTimeInForce;
postOnly?: boolean;
expiresAt?: string;
clientOrderId?: string;
};
type LimitOrderResponse = {
orderId: string;
status:
| "pending"
| "open"
| "partially_filled_open"
| "filled"
| "cancelled"
| "expired"
| "failed";
venue: Venue;
venueOrderId?: string | null;
reservedCostRaw?: string | null;
limitPriceRaw: string;
limitSizeRaw: string;
filledSizeRaw: string;
remainingSizeRaw: string;
};
const client = createAggClient({
baseUrl: "https://api.agg.market",
appId: "your-app-id",
});
async function placeLimitOrder(body: LimitOrderRequest) {
return client.request<LimitOrderResponse>("/execution/limit-orders", {
method: "POST",
body: JSON.stringify(body),
});
}
const order = await placeLimitOrder({
venue: "polymarket",
venueMarketOutcomeId: "vmo_...",
side: "buy",
limitPriceRaw: "200000", // $0.20
sizeRaw: "5000000", // 5 contracts
timeInForce: "GTC",
clientOrderId: `my-app-${crypto.randomUUID()}`,
});
console.log(order.orderId, order.status);
For GTD orders, include a future ISO expiresAt value:
await placeLimitOrder({
venue: "polymarket",
venueMarketOutcomeId: "vmo_...",
side: "buy",
limitPriceRaw: "350000",
sizeRaw: "10000000",
timeInForce: "GTD",
expiresAt: new Date(Date.now() + 60 * 60 * 1000).toISOString(),
clientOrderId: `hourly-resting-${crypto.randomUUID()}`,
});
Monitor Until Open Or Terminal
POST /execution/limit-orders creates the AGG order and schedules venue submission. Treat the
initial response as an admission result, then poll the order row until it is open or terminal.
const terminalStatuses = new Set(["filled", "cancelled", "expired", "failed"]);
async function waitForOrder(orderId: string) {
while (true) {
const page = await client.getExecutionOrders({ orderId, limit: 1 });
const current = page.data[0];
if (!current) {
throw new Error(`Order ${orderId} was not found`);
}
if (current.status === "open" || terminalStatuses.has(current.status)) {
return current;
}
await new Promise((resolve) => setTimeout(resolve, 1500));
}
}
const current = await waitForOrder(order.orderId);
if (current.status === "open") {
console.log("Venue order is live");
}
Open orders reserve balance or shares. When an order fills, AGG updates positions and releases unused reservation. When an order fails, expires, or is cancelled, AGG releases the remaining reservation.
Cancel An Order
Use the same typed-wrapper pattern for cancellation:
type CancelLimitOrderResponse = {
quoteId: string | null;
orderIds: string[];
status: "cancelled" | "cancel_pending";
};
async function cancelLimitOrder(orderId: string) {
return client.request<CancelLimitOrderResponse>(
`/execution/orders/${encodeURIComponent(orderId)}/cancel`,
{
method: "POST",
body: JSON.stringify({}),
},
);
}
const cancel = await cancelLimitOrder(order.orderId);
if (cancel.status === "cancel_pending") {
// Keep polling getExecutionOrders until the order becomes cancelled or terminal.
}
Cancelling is valid for queued and open limit orders. Terminal orders cannot be cancelled.
Venue Support
Supported timeInForce and post-only behavior differs by venue:
| Venue | timeInForce values | postOnly |
|---|---|---|
| Polymarket | GTC, GTD, FOK, FAK | yes |
| Limitless | GTC, FOK | yes |
| Predict | GTC, GTD | no |
| Hyperliquid | GTC, IOC, ALO | yes |
| Myriad | GTC, GTD, FOK, FAK | no |
AGG rejects unsupported venue/time-in-force/post-only combinations before the order reaches the venue.
Recommended UX
- Show the venue name clearly. Limit orders do not smart-route across venues.
- Show raw-price equivalents as user-friendly cents or percentages, but submit six-decimal raw strings to the API.
- Disable
GTDsubmission until the user chooses a future expiration. - Show
pendingas "submitting" and keep the cancel action disabled until the order is open or explicitly cancellable. - Poll
GET /execution/ordersafter page load so refreshed tabs recover open orders. - Store
clientOrderIdin your own system for support and reconciliation.