# Orders & OMS

Orders are **intents**. You submit what you want; the platform composes, signs,
and dispatches it to the venue, then reports the outcome over
[`/ws/risk`](https://docs.troncharts.xyz/docs/realtime/risk/). One endpoint set covers every wired venue.

Every write on this page needs a non-`readonly` credential. `cancel`,
`cancel-all`, and `flatten` accept `liquidation`; everything else — place,
modify, reverse, chase, and the bracket calls — needs `fullTrading`. The rule
is that `liquidation` may reduce exposure, never add it. A `readonly`
credential is refused with `403 tier_readonly`, a `liquidation` credential on a
`fullTrading` route with `403 tier_insufficient`. See
[Scopes & tiers](https://docs.troncharts.xyz/docs/auth/scopes/).

## Place an intent

`POST /api/v1/oms/intents`

```bash
curl -s https://api.troncharts.xyz/api/v1/oms/intents \
  -H "authorization: Bearer $TOKEN" \
  -H "x-tenant-slug: $TC_TENANT_SLUG" \
  -H 'content-type: application/json' \
  -H "idempotency-key: $(uuidgen)" \
  -d '{
    "venue": "hyperliquid",
    "symbol": "BTC.HL",
    "side": "buy",
    "type": "limit",
    "qty": "0.01",
    "price": "60000",
    "timeInForce": "Gtc"
  }'
```

| Field | Notes |
| --- | --- |
| `venue` | Required. One of `hyperliquid`, `aster`, `polymarket`, `kalshi`, `paper`. |
| `symbol` | Required, venue-suffixed (`BTC.HL`). From `GET /api/v1/symbols/{venue}`. |
| `side` | `buy` / `sell`. |
| `type` | `market`, `limit`, `stop`, `stop_limit`, `take_profit`. |
| `qty` | Required. Decimal string preferred. |
| `price` | Required for `limit`. |
| `triggerPrice` | Required for `stop`, `stop_limit`, `take_profit`. |
| `stopLimitPrice` | Required for `stop_limit` — the resting limit price, alongside `triggerPrice`. Omitting it is a `400 stopLimitPrice_required`. |
| `reduceOnly` | Never increases exposure. |
| `timeInForce` | `Gtc` / `Ioc` / `Alo`. |
| `leverage` | Checked at compose time against the effective per-venue cap. |
| `accountId` | Optional — defaults to the credential's active account. Set it to place on a specific owned account. |
| `clientOrderId` | Your own correlation id, echoed back on the response and on the WS frames. |

Sandbox orders go in as `venue: "paper"` against a paper account.
`GET /api/v1/venues` is capability discovery — the adapters wired in this
deploy and what each one supports. It is not this enum: `b3` is listed there
but compose rejects it (paper B3 orders go in as `paper`), and `paper` is never
listed there.

The response carries the **intent id**. Subscribe to the `Order-Intent-Changed`
topic on `/ws/risk` and match `Order-Intent-Update` frames by their `intentId`
— they carry the venue order id, the last event, and the terminal state.

:::caution[Trailing stops are not accepted]
`trailing_stop` is a deliberate, permanent defer. Build it client-side as
cancel-and-replace if you need it.
:::

## Cancel, modify, and the bulk operations

| Endpoint | Does |
| --- | --- |
| `POST /api/v1/oms/cancel` | Cancel one working order by `venueOrderId` — the venue's id, not the intent id. Read it from `GET /api/v1/accounts/{id}/orders` or the `Open-Orders-Update` frames. |
| `POST /api/v1/oms/modify` | Replace a working order's price, qty, or trigger by `intentId`. Resolves a new intent id. |
| `POST /api/v1/oms/cancel-all` | Cancel every working order on the account. |
| `POST /api/v1/oms/flatten` | Close every open position on the account. |
| `POST /api/v1/oms/reverse` | Close a position and open the opposite side. |
| `POST /api/v1/oms/chase` | Cancel-and-replace toward the touch. |

```bash
curl -s https://api.troncharts.xyz/api/v1/oms/cancel \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -H "x-tenant-slug: $TC_TENANT_SLUG" \
  -H "idempotency-key: $(uuidgen)" \
  -d '{ "venueOrderId": "…" }'
```

```ts
await sdk.oms.modify({ intentId, newPrice: 59500 }, idempotencyKey)
```

Modify takes `newPrice`, `newQty`, `newTriggerPrice`, and `newStopLimitPrice`.
Unlike compose, these are numbers only — a decimal string is rejected.

## Brackets

There is **no inline bracket field on compose**. Place the entry, then attach
the OCO legs:

| Endpoint | Does |
| --- | --- |
| `POST /api/v1/oms/brackets/attach` | Attach TP and/or SL to an entry by `parentIntentId`. |
| `POST /api/v1/oms/brackets/attach-to-position` | Attach to an already-open position. |
| `POST /api/v1/oms/brackets/modify` | Move an existing leg. |

```bash
curl -s https://api.troncharts.xyz/api/v1/oms/brackets/attach \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -H "x-tenant-slug: $TC_TENANT_SLUG" \
  -d '{ "parentIntentId": "…", "tpPrice": 64000, "slPrice": 58000 }'
```

At least one of `tpPrice` / `slPrice` must be set. When the parent is still
unfilled the response carries `staged: true` — the legs arm on fill.

## Venue-specific fields

Some venues accept extras: `asterTimeInForce`, `asterKind`, `clientId`. They
are ignored by venues that don't use them, but read `GET /api/v1/venues` for
what each adapter actually supports rather than sending them blind.

## Leverage

Pass `leverage` on the intent itself. It is validated at compose time against
the effective per-venue cap, which comes from the account's **trading group** —
groups scope fee schedules, leverage caps, and venue/symbol allowlists. An
intent above the cap is rejected at compose, before anything reaches the venue.