# Order Placement

Use the order endpoints to simulate, submit, query, and cancel perpetual orders.

## Before You Submit

1. Get the EIP-712 domain from `GET /v1/rpc/config`.
2. Get the product from `GET /v1/product`.
3. Check that `status` is `ACTIVE`.
4. Check `lotSize`, `tickSize`, price limits, quantity limits, and `marginMode`.
5. Check the applicable subaccount balance.
6. For an isolated product, convert balance to its quote-token pool.
7. Create a fresh `nonce` and `signedAt` value.
8. Sign the exact `TradeOrder` message.

See [Message Signing](/developer-guides/trading-api/message-signing).

## Submit an Order

```http
POST /v1/order
```

The body has a `data` object and a top-level `signature`.

Main `data` fields:

| Field                  | Requirement                                                      |
| ---------------------- | ---------------------------------------------------------------- |
| `sender`               | Owner or linked-signer address that made the signature.          |
| `subaccount`           | Bytes32 subaccount name.                                         |
| `nonce`                | Unix nanoseconds as a string.                                    |
| `signedAt`             | Unix seconds.                                                    |
| `type`                 | `MARKET` or `LIMIT`.                                             |
| `quantity`             | Positive decimal string, or `"0"` for a close order.             |
| `side`                 | `0` for buy or `1` for sell.                                     |
| `onchainId`            | Numeric product ID from product metadata.                        |
| `engineType`           | `0` for a perpetual product.                                     |
| `clientOrderId`        | Optional subaccount-scoped ID.                                   |
| `reduceOnly`           | Optional Boolean. Required for a close order.                    |
| `close`                | Optional Boolean that sizes the order from the current position. |
| `stopPrice`            | Optional mark-price trigger.                                     |
| `stopType`             | `0` for take profit or `1` for stop loss.                        |
| `expiresAt`            | Optional Unix seconds.                                           |
| `groupId`              | Optional UUID for linked orders.                                 |
| `groupContingencyType` | Optional `0` for OTO or `1` for OCO.                             |

A limit order also requires:

| Field         | Requirement                                |
| ------------- | ------------------------------------------ |
| `price`       | Positive decimal string.                   |
| `timeInForce` | `GTD`, `IOC`, or `FOK`.                    |
| `postOnly`    | Boolean. It can be `true` only with `GTD`. |

A market order does not send `price`, `timeInForce`, or `postOnly`.

## Product Validation

* `quantity` must be divisible by `lotSize`.
* `quantity` must not exceed `maxQuantity`.
* `price` and `stopPrice` must be divisible by `tickSize`.
* `price` must be between `minPrice` and `maxPrice`.
* A reduce-only order must not increase or flip a position.
* A close order requires `quantity: "0"` and `reduceOnly: true`.

The exchange also checks margin, position notional, open interest, linked-order rules, and order expiry.

## Dry Run

```http
POST /v1/order/dry-run
```

Use the same unsigned `data` shape as order submission. A dry run returns:

* `marginRequired` and `marginAvailable`.
* `totalUsedMargin`.
* `riskUsed` and `riskAvailable`.
* A result `code`.

A dry run is a point-in-time estimate. Market state can change before the signed order arrives.

## Immediate Response and Block Execution

`POST /v1/order` returns HTTP `201` when the request is accepted. The response contains the order ID, optional client order ID, `filled`, and a result code.

Taker orders wait in the execution block. Their immediate response has `filled: "0"`. Use WebSocket `OrderUpdate` and `OrderFill` messages for the later result.

See [Block Execution](/trading/perpetual-futures/block-execution).

## Order Status

| Status           | Meaning                                              |
| ---------------- | ---------------------------------------------------- |
| `NEW`            | Working order on the book.                           |
| `PENDING`        | Accepted trigger or linked order that is not active. |
| `FILLED_PARTIAL` | Working order with one or more fills.                |
| `FILLED`         | Complete order.                                      |
| `REJECTED`       | Order rejected during execution.                     |
| `CANCELED`       | Remaining quantity canceled.                         |
| `EXPIRED`        | Order expiry reached.                                |

The `triggered` field gives the trigger state for stop and linked orders. `rejectedReason` can give the engine rejection reason.

## Query Orders and Fills

* `GET /v1/order?subaccountId=<uuid>` lists orders.
* `GET /v1/order/{id}` returns one order.
* `GET /v1/order/{id}/group` lists active orders in the same group.
* `GET /v1/order/fill?subaccountId=<uuid>` lists subaccount fills.
* `GET /v1/order/trade?productId=<uuid>` lists product trades.

Use cursor pagination. Order and fill time-range queries can have additional range limits. Check the OpenAPI schema for all filters.

## Cancel Orders

```http
POST /v1/order/cancel
```

The signed `CancelOrder` data contains `sender`, `subaccount`, and `nonce`. The request can contain `orderIds`, `clientOrderIds`, or both. The combined maximum is `200` unique IDs.

The response contains one result per target. An accepted HTTP request does not prove that each target was canceled.

If the target order is in the current execution block, the cancel enters the same block. The order can fill before the cancel is applied. Use WebSocket updates for final state.

## Cancel All Orders

```http
POST /v1/order/cancel-all
```

Use this endpoint to cancel every open order for one subaccount. The cancellation applies across all products and margin modes, including the unfilled quantity of partially filled orders. It does not affect orders belonging to another subaccount.

Cancel-all uses the same EIP-712 `CancelOrder` type as a targeted cancellation. Sign `sender`, `subaccount`, and a fresh `nonce`, then send the signed data without `orderIds` or `clientOrderIds`:

```json
{
  "data": {
    "sender": "0x...",
    "subaccount": "0x...",
    "nonce": "1712019600000000000"
  },
  "signature": "0x..."
}
```

The owner or an active linked signer for the subaccount can authorize the request. HTTP `202` returns one result for each order that the operation attempted to cancel. If the subaccount has no open orders, the request still succeeds and returns `{ "data": [] }`.

Cancel-all is subaccount-scoped rather than ID-scoped, so the 200-ID limit for targeted cancellations does not apply. Treat the response as acceptance and use WebSocket order updates to confirm final order states.

Cancel-all consumes 1 account point for each order cancellation it attempts. Failed cancellation results still consume points. If the subaccount has no resting orders, the request consumes a minimum of 1 account point. See [System Limits](/developer-guides/trading-api/system-limits#how-points-are-charged) for rate-limit configuration.

## Replace an Order

The current public API does not have an amend or batch-order endpoint. To replace an order, cancel the old order and submit a new order. These are separate requests and are not atomic.

Use a unique `clientOrderId` to reconcile each request.
