AGG is currently in alpha. APIs, components, and docs may change.
Agg.market — Prediction Market Aggregator logo

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

1
User signs in

The request uses user-tier auth: x-app-id plus the user's bearer token.

2
Find an outcome

Use discovery, market pages, or orderbook APIs to select the exact venueMarketOutcomeId for the venue where the order should rest.

3
Check funding or position inventory

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.

4
Place the limit order

Call POST /execution/limit-orders. The response is usually pending first because the executor submits to the venue asynchronously.

5
Poll or stream order state

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.

6
Cancel when needed

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:

FieldMeaningExample
limitPriceRawPrice in USDC-style six decimals. 200000 means $0.20."200000"
sizeRawContract/share size in six decimals. 5000000 means 5."5000000"
timeInForceVenue-supported duration or execution instruction."GTC"
clientOrderIdOptional 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:

VenuetimeInForce valuespostOnly
PolymarketGTC, GTD, FOK, FAKyes
LimitlessGTC, FOKyes
PredictGTC, GTDno
HyperliquidGTC, IOC, ALOyes
MyriadGTC, GTD, FOK, FAKno

AGG rejects unsupported venue/time-in-force/post-only combinations before the order reaches the venue.

  • 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 GTD submission until the user chooses a future expiration.
  • Show pending as "submitting" and keep the cancel action disabled until the order is open or explicitly cancellable.
  • Poll GET /execution/orders after page load so refreshed tabs recover open orders.
  • Store clientOrderId in your own system for support and reconciliation.
Place Limit Order API

Full request and response schema for POST /execution/limit-orders.

Funding & Withdrawals

Prepare balances before placing live buy orders.