# Place a limit, stop or stop-limit order

URL: https://docs.fxapis.com/api-reference/trading/place-a-limit-stop-or-stop-limit-order

> Place a limit, stop or stop-limit order. A success here means placed and waiting, not filled — the broker answers 10008 PLACED and the order is working until…

`POST https://api.fxapis.com/v1/accounts/{id}/orders/pending`

A success here means **placed and waiting**, not filled — the broker answers `10008 PLACED` and the order is `working` until it triggers.

A limit waits for a better price (buy below the market, sell above); a stop waits for a worse one and is how a breakout is traded (buy above, sell below). When fxapis has a recent price for the symbol on this account, the wrong side is refused before anything is sent, with a message naming the order you probably meant; otherwise the broker answers with its own `INVALID_PRICE`.

Authentication: `Authorization: Bearer <API key>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string (uuid) | yes |  |
| `idempotency-key` | header | string | no | Any unique string, usually a UUID. A retry with the same key and body returns the first answer instead of placing a second order; the same key with a different body is refused. |

#### Request body (application/json, required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `symbol` | string | no | As the broker names it. Example: `"EURUSD"` |
| `instrument` | string | no | Instead of `symbol`: an instrument from `GET /v1/instruments`, traded under this account's own broker symbol for it (`XAUUSD` may be `XAUUSD.a` or `GOLD` at the broker). The order records both. Refused with `INSTRUMENT_NOT_OFFERED` or `INSTRUMENT_AMBIGUOUS` when the account's broker has no single match. Example: `"XAUUSD"` |
| `side` | "buy" \| "sell" | yes |  |
| `kind` | "limit" \| "stop" \| "stop_limit" | yes | A **limit** waits for a better price: buy below the market, sell above it. A **stop** waits for a worse one and is how a breakout is traded: buy above, sell below. Getting these backwards is the commonest mistake here, so the wrong side is refused with a message saying which you meant. |
| `volume` | string | yes | Example: `"0.01"` |
| `price` | string | yes | The price the order waits at. Example: `"1.12800"` |
| `stopLimitPrice` | string | no | Required for stop_limit: the limit placed once the stop triggers. Example: `"1.12780"` |
| `stopLoss` | string | no | Example: `"1.12400"` |
| `takeProfit` | string | no | Example: `"1.13600"` |
| `expiresAt` | string (date-time) | no | When the broker should drop it. Omit for good-till-cancelled. |
| `comment` | string | no | Example: `"breakout"` |
| `clientOrderId` | string | no | Example: `"sig-43-user-7"` |

#### Responses

- `201`
- `400`
- `401`
- `402`
- `403`
- `404`
- `409`
- `422`
- `503`

Failures return `{ "error": { "code", "message" } }`; every code is listed at https://docs.fxapis.com/errors.

#### 201 response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `data` | object | no |  |
| `data.id` | string (uuid) | no |  |
| `data.accountId` | string (uuid) | no |  |
| `data.clientOrderId` | null \| string | no | Your own reference, echoed back. |
| `data.symbol` | string | no | The broker symbol traded. |
| `data.instrument` | null \| string | no | The instrument the order named, when it named one; `symbol` is what it was traded as. Example: `"XAUUSD"` |
| `data.side` | "buy" \| "sell" | no |  |
| `data.type` | "market" \| "limit" \| "stop" \| "stop_limit" | no |  |
| `data.intent` | "open" \| "close" \| "modify" \| "cancel" | no | What this order was for. A close is an order, with the same record and the same failed/unknown distinction as an open — `modify` covers moving a stop, which changes what the account risks. |
| `data.brokerPositionId` | null \| string | no | The broker's position ticket. On a close or a stop change, the position it acted on. On an opening order, the position it opened — pass it to `POST /v1/accounts/{id}/positions/{positionId}/close`. Set when the order fills if the terminal reports it; for an order filled by an older terminal, or a pending order that fills later, once the broker's deal history for it has been read. Null until known. |
| `data.volume` | null \| string | no | Requested volume, in lots. |
| `data.stopLoss` | null \| string | no | Absolute price, not a distance. |
| `data.takeProfit` | null \| string | no | Absolute price, not a distance. |
| `data.state` | "accepted" \| "validating" \| "sending" \| "working" \| "completed" \| "filled" \| "partially_filled" \| "rejected" \| "failed" \| "unknown" \| "cancelled" \| "expired" | no |  |
| `data.stateDetail` | null \| string | no |  |
| `data.needsReconciliation` | boolean | no | True while we are confirming the result with the broker. Never resend such an order; poll it. |
| `data.retcode` | null \| integer | no | The broker's own MT5 return code, unmodified. 10009 is a completed request. |
| `data.retcodeText` | null \| string | no |  |
| `data.brokerOrderId` | null \| string | no | The broker's ticket. What their statement shows. |
| `data.brokerDealId` | null \| string | no |  |
| `data.filledVolume` | null \| string | no | What actually filled, which can be less than requested. |
| `data.filledPrice` | null \| string | no | What it actually filled at, which is rarely the requested price. |
| `data.sentAt` | null \| string (date-time) | no |  |
| `data.settledAt` | null \| string (date-time) | no | When an answer arrived. |
| `data.reconciledAt` | null \| string (date-time) | no | Set when a result was confirmed with the broker after the fact. |
| `data.createdAt` | string (date-time) | no |  |