> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agg.market/llms.txt
> Use this file to discover all available pages before exploring further.

# Limit Orders

> Place, monitor, and cancel venue-specific limit orders through the Execution API

<Info>
  Limit orders require a signed-in user session and live execution mode. Start with
  [Authentication](/recipes/authentication) and [Funding & Withdrawals](/recipes/deposits)
  before placing live orders.
</Info>

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`](/api-reference/execution/fillmanaged) instead. Limit orders are venue-specific:
you choose one `venue`, one `venueMarketOutcomeId`, a side, a limit price, and a size.

## How It Works

<Steps>
  <Step title="User signs in">
    The request uses user-tier auth: `x-app-id` plus the user's bearer token.
  </Step>

  <Step title="Find an outcome">
    Use discovery, market pages, or orderbook APIs to select the exact `venueMarketOutcomeId`
    for the venue where the order should rest.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Place the limit order">
    Call `POST /execution/limit-orders`. The response is usually `pending` first because the
    executor submits to the venue asynchronously.
  </Step>

  <Step title="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.
  </Step>

  <Step title="Cancel when needed">
    Call `POST /execution/orders/{orderId}/cancel` for queued or open orders. Cancels can return
    `cancel_pending` before the venue confirms cancellation.
  </Step>
</Steps>

## 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.

<Warning>
  `clientOrderId` must be unique per user. Reusing it for the same user returns a conflict.
</Warning>

## 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.

```ts theme={null}
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:

```ts theme={null}
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.

```ts theme={null}
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:

```ts theme={null}
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 `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.

## Related

<CardGroup cols={2}>
  <Card title="Place Limit Order API" icon="book-open" href="/api-reference/execution/place-limit-order">
    Full request and response schema for `POST /execution/limit-orders`.
  </Card>

  <Card title="Funding & Withdrawals" icon="cube" href="/recipes/deposits">
    Prepare balances before placing live buy orders.
  </Card>
</CardGroup>
