# `order` Places one or more orders. Every order in the batch is signed together and applied in array order. `POST /exchange` · type `order` Place one or more orders (limit, market, trigger, TP/SL). · [Agent-signed](/api/signing.md#flow-2--agent-signing) - Access: Agent-signed - Not this? [`modify2`](/api/exchange/modify2.md) — when you want to change price or size of a resting order without losing queue position ### Action fields Listed in the node's field order — keep it when encoding the action. - `type` (string, required) — Must be `order`. Values: `"order"`. - `grouping` (string, required) — How the batch is interpreted as a group. Values: `"na"`, `"normalTpsl"`, `"positionTpsl"`, `"normalTrigger"`, `"reversePosition"`, `"closeAll"`. - `orders` (OrderBody[], required) — Order bodies; at most 50 per action. - `a` (integer · uint32, required) — Instrument's external id — the `index` value from `perpMeta`; Outcome markets use the `instrument_id`. Long form: `asset`. - `b` (boolean, required) — `true` to buy, `false` to sell. Long form: `isBuy`. - `p` (string, required) — Limit price. The literal `"bbo"` prices at the current best bid/offer. Long form: `limitPx`. - `s` (string, required) — Size in base units. Long form: `sz`. - `r` (boolean, optional) — Reduce-only. Defaults to `false`. Long form: `reduceOnly`. - `t` (oneOf, required) — Either a `limit` or a `trigger` body. Long form: `orderType`. - One of · variant 1: - `limit` (object, required) - `tif` (string, required) — Time-in-force. Values: `"Gtc"`, `"Ioc"`, `"Alo"`, `"Gtd"`, `"FrontendMarket"`. - One of · variant 2: - `trigger` (object, required) - `isMarket` (boolean, required) — Fill at market once triggered. - `triggerPx` (string, required) — Price at which the order activates. - `tpsl` (string, optional) — Take-profit or stop-loss. Values: `"tp"`, `"sl"`. - `c` (string, optional) — Client order id, used later by `cancelByCloid`. Long form: `cloid`. - `m` (string, optional) — Margin mode. Long form: `marginMode`. Optional: when omitted the node routes the order to the account's current margin mode for this market (its saved position profile, `cross` for an account that has never set one) — so the same body can land on a different mode after an `updateMarginMode`. API clients should send `m` explicitly. The margin mode is part of the position key, so it also selects which position the order opens into or reduces. Values: `"cross"`, `"isolated"`. - `expiresAt` (integer · uint64, optional) — Required when `tif` is `Gtd`. Unix milliseconds, and must be in the future. - `builder` (Builder, optional) — Optional builder code. The order signature covers this object. - `b` (string · address, required) — Builder wallet address. - `f` (integer · uint32, required) — Fee in tenths of a basis point: `rate = f / 100,000`, so `f = 10` is 1 bp (`0.01%`). ### Request example The signed envelope; `signature` and `nonce` are placeholders — see Signing. ```bash curl -X POST https://rpc.txflow-testnet.xyz/exchange \ -H 'Content-Type: application/json' \ -H 'x-api-version: 2026-08-16' \ -d '{"action":{"type":"order","grouping":"na","orders":[{"a":1,"b":true,"p":"50000.0","s":"0.01","r":false,"t":{"limit":{"tif":"Gtc"}}}]},"signature":{"r":"0x","s":"0x","v":27},"nonce":1757992743994,"vaultAddress":null,"signatureChainId":null}' ``` ### Response · PlaceOrder (200) - `code` (integer) — `0` on success. - `data` (object) - `data` (object) - `statuses` (ActionStatus[]) — Exactly one entry for the whole action, however many orders or cancels it carries. - One of · variant 1: - string — Accepted. By default this means accepted by consensus, not yet executed; send `"confirm": "executed"` in the request body to wait for the execution result. - One of · variant 2: - `error` (string) — Why execution failed. - `type` (string) — The action's internal name, which does not always match the request `type`. Values: `"PlaceOrder"`. - `status` (string) — A rejected request returns `err` with a non-zero `code` and the reason in `message` (or `response`). Values: `"ok"`. ### Response example ```json { "status": "ok", "code": 0, "data": { "type": "PlaceOrder", "data": { "statuses": [ "success" ] } } } ``` ## Outcome orders For an Outcome market, `a` is its `instrument_id`. YES is the long leg and NO the short leg; `b` and `r` together encode the leg and direction: | Intent | `b` | `r` | | ------ | --- | --- | | Buy YES | `true` | `false` | | Buy NO | `false` | `false` | | Sell YES | `false` | `true` | | Sell NO | `true` | `true` | `p` is the price of the traded leg, between 0 and 1: buying NO at `0.30` sends `b: false, r: false, p: "0.30"`. Outcome orders use `grouping: "na"` and do not support trigger/TP-SL order types. Time-in-force must be `Gtc`, `Gtd`, or `Alo`; an `Ioc` order is rejected with `Outcome limit orders only support GTC, GTD, and ALO orders`, reported asynchronously on [`outcomeOrderUpdate`](/api/websocket/outcomeOrderUpdate.md). The initial HTTP response can be an asynchronous acceptance (`{"status":"ok","traceId":…}`) rather than a fill. If the queued order fails, [`outcomeOrderUpdate`](/api/websocket/outcomeOrderUpdate.md) pushes the reason under that `traceId`; successes are not pushed. Follow the matching lifecycle on [`outcomeOrderUpdates`](/api/websocket/outcomeOrderUpdates.md) or read [`outcomeFrontendOpenOrders`](/api/info/outcomeFrontendOpenOrders.md). Order bodies use abbreviated keys. The long forms noted above are accepted on input, but the abbreviated keys are what the signature covers. The optional `builder` object is documented under [Attach a builder to an order](/api/exchange.md#attach-a-builder-to-an-order). ## Order body Fields as listed under `orders` in **Action fields** above. ### Price, size, and client order id | Rule | Rejected with | | ---- | ------------- | | `p` is a multiple of the instrument's `priceTick` from [`perpMeta`](/api/info/perpMeta.md), with no more decimals than the tick | `Price precision does not match the tick size: ` / `Tick size does not match` | | `s` has at most `szDecimals` decimals and lies between the minimum size and `maxLimitOrderSize` / `maxMarketOrderSize` | `Minimum order amount is ` / `Maximum limit order amount is …` | | A limit price stays inside the oracle price band | `Order buy price is not within the price limit (Minimum price: …; Maximum price: …)` | | `c` is any string up to 64 bytes, unique among your open orders. A `0x` prefix is reserved for liquidity-provider accounts, on every market | `cloid length exceeds maximum` / `Duplicate client order ID ` / `Invalid cloid format` | ## Order type A limit order carries a time-in-force: ```json { "limit": { "tif": "Gtc" } } ``` | `tif` | Behavior | | ----- | -------- | | `Gtc` | Good-til-canceled; rests on the book | | `Ioc` | Immediate-or-cancel; unfilled remainder is canceled | | `Alo` | Add-liquidity-only (post-only); rejected if it would take | | `Gtd` | Good-til-date; requires `expiresAt` | | `FrontendMarket` | Treated as a market order | A trigger order carries a trigger price instead: ```json { "trigger": { "isMarket": true, "triggerPx": "48000.0", "tpsl": "sl" } } ``` `tpsl` is `tp` (take-profit) or `sl` (stop-loss). Trigger orders are only accepted under a `normalTpsl`, `positionTpsl`, or `normalTrigger` grouping; sending one with `grouping: "na"` is rejected with `Trigger orders are not supported for grouping na`. ### Triggered is not filled A TP/SL that reaches its trigger price is **fired**, not guaranteed to execute. Two separate things happen: 1. **Trigger** — the protection order's trigger state becomes `Triggered`, and in a TP/SL pair the **other side is canceled at the same moment** (`Canceled` trigger state). This is OCO: it happens on trigger, not on fill. 2. **Execution** — the fired order is then submitted to the matcher like any other order, and can be fully filled, partially filled, canceled, or rejected. A fired order that does not fill does **not** revert to a pending protection order — it is in a terminal state and the position is left unprotected. Common reasons the fired leg does not fill: | Outcome | Why | | ------- | --- | | Canceled with no or partial fill | A fired market order carries the oracle price-protection band; the remainder past the band, or past the book's available liquidity, is canceled | | Rejected | The limit price falls outside the price band or off the tick, or the instrument is halted / delisted, or the order is over the open-interest cap | | Skipped entirely | The underlying position is already flat (closed, liquidated, or closed by the other side of the pair) when the trigger fires | Because the sibling was already canceled in step 1, a failed fill leaves **neither** protection order live. Re-arm the protection yourself after confirming the outcome. Confirm the result rather than assuming it: read the pair back with [`tpslOrders`](/api/info/tpslOrders.md) (live) and [`historicalTpslOrders`](/api/info/historicalTpslOrders.md) (terminal, carrying `cancelSource` / `cancelReason`), check the resulting order on [`historicalOrders`](/api/info/historicalOrders.md), and follow [`orderUpdates`](/api/websocket/orderUpdates.md) for the live transitions. ## Next steps Read resting orders back with [`frontendOpenOrders`](/api/info/frontendOpenOrders.md). To reprice or resize a resting order, use [`modify2`](/api/exchange/modify2.md).