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

# Route your traders' orders

> Read one of your traders' accounts, account data and market data, and route the orders they place in your interface, from your backend with your API key and their id.

Run your trading screens on your traders' own accounts. Once a trader has connected an account or
opened your white-label paper, your backend reads their accounts, positions, orders and market data,
and routes the orders they place in your interface, much as the trdrs trading app does. Every order
is the trader's own: they place it on your screen, on their own account, and your backend carries it
to trdrs and shows them what comes back.

Use this page when you build the screens behind your Connect, after the
[Connect quickstart](/guides/connect-quickstart). By the end your backend lists a trader's accounts,
checks and routes their order, moves and cancels it, follows the account on its live stream, and you
know how to stop all of it for one trader.

## Before you start

1. Your app's API key. The [Connect quickstart](/guides/connect-quickstart) creates one.
2. A trader who connected through your Connect, such as `trader-test-1` from the quickstart, with
   the Demo they opened.
3. `TRDRS_API_BASE_URL` and `TRDRS_API_KEY` in your shell, and the trader's account
   in `PROVIDER` and `ACCOUNT`, as the quickstart sets them.

## Name the trader on every request

Every request for a trader carries your API key and your own id for the trader:

```http theme={null}
Authorization: Bearer trdrs_ck_sandbox_...
x-trdrs-trader: trader-test-1
```

The request runs as that trader, on their own accounts only: the accounts they connected through
your Connect and the Demo they opened from your white-label paper. The id is the one your Connect
links name. Trading never creates a trader: an id becomes one of your traders the first time a
Connect link names it, and until then every request for it answers `404` `trader_not_found`.

Your app's API key reaches every one of these routes for your traders. A venue's backend calls the
same routes for its own traders with its Venue key, which reaches what its scopes say:

| Venue key scope | What it reaches on the trader's accounts |
| - | - |
| `trader:read` | Their accounts, positions, orders, fills and history, and the account stream; market data, instruments, news and the economic calendar; their risk settings |
| `trader:trade` | Routing their orders, which places, changes and cancels them; their exit plans; changes to their risk settings. It also reads everything `trader:read` reads on these routes |

<Warning>
  Your API key routes orders on the accounts of every one of your traders. Keep it on your server,
  never in a browser or a mobile app. A request that carries a cookie or a browser
  `Origin` beside it is refused, so your server is the one place that calls these routes.
</Warning>

<Steps>
  <Step title="List the trader's accounts">
    Read every account the trader holds through your Connect.

    ```bash theme={null}
    curl --fail-with-body "$TRDRS_API_BASE_URL/api/account/list" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1"
    ```

    The response's `accounts` lists each one with its `provider` and `accountNumber`, which name the
    account on every other route, its `balance`, `openPositions` and `capabilities`, and its
    `accountId`, the id a connected Connect link names in `result`. Only this trader's accounts
    appear.
  </Step>

  <Step title="Read one account">
    Read the account as one moment: its balance, open positions, working orders and exits, which
    always agree with each other.

    ```bash theme={null}
    curl --fail-with-body "$TRDRS_API_BASE_URL/api/account/snapshot?provider=$PROVIDER&account=$ACCOUNT" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1"
    ```

    `GET /api/account/instruments` lists the symbols the account trades, for your symbol picker, and
    the other account routes read positions, orders, fills and history the same way, with the
    account named in the query.
  </Step>

  <Step title="Check what the account may do">
    When the trader picks an instrument, ask what the account may do on it before they order. It runs
    the checks an order runs, in the same order, without sending anything, and on the paper book it
    readies the instrument's prices for the order that follows.

    ```bash theme={null}
    curl --fail-with-body "$TRDRS_API_BASE_URL/api/trading/actions?provider=$PROVIDER&account=$ACCOUNT&instrument=HYPERLIQUID%3ABTC" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1"
    ```

    `actions` holds one verdict for each action: `open`, `reduce`, `close`, `protect`, `flatten` and
    `cancel`. A blocked action carries the `refusal` the order would get, with its `code` and
    `message`, so your ticket can say why before the trader presses anything.
  </Step>

  <Step title="Route the trader's order">
    When the trader places an order on your screen, send it on to their account. trdrs prices,
    checks, places and records it as it does an order from the trdrs trading app. This one is a
    limit order below the market, so it rests:

    ```bash theme={null}
    curl --fail-with-body -X POST "$TRDRS_API_BASE_URL/api/trading/order?provider=$PROVIDER&account=$ACCOUNT" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1" \
      -H "Content-Type: application/json" \
      -d '{ "instrument": "HYPERLIQUID:BTC", "side": "buy", "qty": 0.01, "orderType": "limit", "limitPrice": 90000, "clientOrderId": "trader-test-1-entry-1" }'
    ```

    The example assumes the market near 100,000, so a buy at 90,000 rests. The response names the
    order with its `providerOrderId` and a `filledQty` of `0`. Keep the id: it's how you move or
    cancel the order.

    Mint `clientOrderId` once, when the trader presses the button, and send the same id on every
    retry: a second request with it answers `409` and never places a second order. trdrs records
    every order request with the key that sent it and the trader whose order it is.
    [Place your first order](/guides/place-your-first-order) covers order types, exits and every
    refusal.
  </Step>

  <Step title="Move or cancel it">
    Move the working order to a new price, under a new `clientOrderId` of its own:

    ```bash theme={null}
    curl --fail-with-body -X POST "$TRDRS_API_BASE_URL/api/trading/replace?provider=$PROVIDER&account=$ACCOUNT" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1" \
      -H "Content-Type: application/json" \
      -d '{ "providerOrderId": "<providerOrderId>", "instrument": "HYPERLIQUID:BTC", "side": "buy", "qty": 0.01, "orderType": "limit", "price": 91000, "clientOrderId": "trader-test-1-move-1" }'
    ```

    Show the trader the `outcome`: `amended` and `replaced` mean the order moved, and the order
    working afterwards is the `providerOrderId` in the response. Then cancel it by that id:

    ```bash theme={null}
    curl --fail-with-body -X POST "$TRDRS_API_BASE_URL/api/trading/cancel?provider=$PROVIDER&account=$ACCOUNT" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1" \
      -H "Content-Type: application/json" \
      -d '{ "providerOrderId": "<providerOrderId>" }'
    ```

    A `200` means the provider accepted the cancel. The account stream, next, tells you what is still
    working.
  </Step>

  <Step title="Follow the account on its stream">
    Don't poll. Open the account stream for the trader: it sends the whole account first, then every
    change, and one stream drives your position panel, your order list and your lock banner together.

    ```bash theme={null}
    curl -N "$TRDRS_API_BASE_URL/api/account/stream?provider=$PROVIDER&account=$ACCOUNT" \
      -H "Authorization: Bearer $TRDRS_API_KEY" \
      -H "x-trdrs-trader: trader-test-1" \
      -H "Accept: text/event-stream"
    ```

    Each `account` event is the whole account at one `revision`: replace what you hold with it, and
    ignore an event at or below the revision you have. A `lock` event says when a risk control has
    locked the account. The stream proves your key and the trader again on every heartbeat, every
    15 seconds, so a revoked or expired key, or a suspended trader, ends it at the next one. On a
    reconnect, replace your state with the fresh snapshot. [Streaming](/api/streaming) describes the
    events.
  </Step>
</Steps>

## Forward your page's requests

Your trading screens run in a browser, which never holds your API key, so your server stands between
them and trdrs. A thin forwarder is enough: your page calls a path on your own server, and your
server sends the same request to trdrs's route with your key and the trader's id, then passes the
answer back. Your screens can then use trdrs's request and response shapes as they are.

* **Forward only the trader routes**: `/api/account/…`, `/api/market/…`, `/api/instruments`,
  `/api/news`, `/api/calendar`, `/api/risk`, `/api/trading/…` and `/api/exit-plans`. Nothing else.
* **Name the trader from your own session.** Add `x-trdrs-trader` from the trader your own sign-in
  verified, never from anything the browser sent.
* **Refuse requests from other sites.** Your session cookie rides every request to your server, so
  answer a cross-site request with nothing, and forward a request that changes anything only when its
  `Origin` is your own site.
* **Send trdrs only what it reads**: the method, the path, the query, the JSON body, and the
  `Accept`, `Content-Type`, `Idempotency-Key` and `Last-Event-ID` headers. Pass back the status, the
  body and `Retry-After`, never a cookie.
* **Pass a stream through as it arrives**, and end it when the browser leaves.

## Prices for futures

Futures prices are licensed to each user, so a trader's futures prices come from a login they
connect through your Connect at a provider that carries them, today Rithmic on their firm's
production system. Without one, the trader's Demo lists no futures, and a futures order answers
`422` `market_data_unavailable` with cause `login_missing`. A Rithmic Test login carries no market
data, so futures can't be traded in the sandbox: build and test with crypto, such as
`HYPERLIQUID:BTC`, whose prices come from public feeds and need no login.
[Providers](/providers) says where each provider's prices come from.

## Suspend a trader

Suspend a trader to stop every request for them at once, for example while you review their
account. Every request for them is then refused with `403` `trader_suspended`, their open streams
close within a heartbeat, and they can't open your white-label paper. Suspending closes no position
and cancels no order.

An owner or an editor of your app suspends a trader in the Connect dashboard's **Traders**, by your
own id for them, and lifts the suspension there. A venue suspends one of its own traders with
`PUT /api/venues/{venueId}/traders/{trader}/suspension` and a Venue key carrying
`venue:configure`, and lifts it with `DELETE` on the same path.

## Handle refusals

These come before any route reads the request:

| You get | It means | What to do |
| - | - | - |
| `400` `trader_required` | The request carried your API key but no `x-trdrs-trader`. | Name the trader. |
| `400` `credential_not_allowed` | The request also carried a cookie or a browser `Origin`. | Call from your server only. |
| `401` `invalid_key` | The key is malformed, revoked or expired, belongs to the other environment, or the owner who created it left your app's owners. | Use a live key for this environment. |
| `403` `permission_denied` | A Venue key lacks the scope the route needs. | Use a key with the scope. |
| `403` `trader_suspended` | You suspended the trader. | Lift the suspension. |
| `404` `trader_not_found` | No Connect link of yours named that id in this environment. | Create a Connect link for the trader first. |

Past these, each route answers as it does for any account: an order can still be refused, for
example `423` `risk_locked` when a risk control has locked the account.
[Place your first order](/guides/place-your-first-order) lists the order refusals.

Market data requests that name a trader are limited per key and trader rather than per your server's
address, so one busy trader never spends another's allowance. [Rate limits](/api/rate-limits) gives
the numbers.

## Test it end to end

1. List `trader-test-1`'s accounts. You see their Demo.
2. Place the limit order above. It rests, and the account stream shows it among the working orders.
3. Move it, then cancel it. The stream shows it at the new price, then gone.
4. Send the order request again with the same `clientOrderId`. You get `409`, and nothing new is
   placed.
5. Add `-H "Cookie: a=b"` to any request. You get `400` `credential_not_allowed`.
6. List the accounts of an id no Connect link named. You get `404` `trader_not_found`.

## The routes this page calls

The account, market and trading routes are the ones the trdrs trading app uses. Each takes your app's
API key, which starts `trdrs_ck_sandbox_` in the sandbox, with the trader it acts for:

| Step | Route |
| - | - |
| Name the trader | The `x-trdrs-trader` header |
| Read the account | `GET /api/account/list`, `/api/account/snapshot`, `/api/account/instruments` and `/api/account/stream` |
| Route orders | `GET /api/trading/actions`, and `POST /api/trading/order`, `/api/trading/replace` and `/api/trading/cancel` |
| Suspend a trader | The Connect dashboard's **Traders** |

If you run a venue and issue accounts to your own traders by your own id, your Venue key reaches
those accounts on the same routes. [Venue accounts](/guides/venue-accounts) shows how to issue one.

## Next steps

<CardGroup cols={2}>
  <Card title="Build a front end" icon="display-code" href="/guides/build-a-front-end">
    Draw your traders' charts, tickets and positions over these routes.
  </Card>

  <Card title="Place your first order" icon="bolt" href="/guides/place-your-first-order">
    Learn every order type, exit and refusal the trading routes give.
  </Card>

  <Card title="Tiles and white-label paper" icon="table-cells" href="/guides/connect-tiles-and-paper">
    Choose your tiles, and reset or retire a trader's Demo.
  </Card>

  <Card title="Pass conformance" icon="list-check" href="/guides/connect-conformance">
    Prove your backend handles the journey and its faults.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.