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

# Track orders

> Follow an order to a terminal state by polling the order endpoint, subscribing to the status stream, or both.

Watch the order until it reaches `COMPLETED`, `ERROR`, or `TIMED_OUT`; every status is defined in the [order lifecycle](/api-reference/order-lifecycle).

## Polling

`GET /v1/orders/{uuid}` returns the full order with no headers; the UUID authorizes the read. Poll every 5 seconds, since transitions wait on block confirmations anyway. An unknown UUID returns `500`, not `404`, so cap failures and check the UUID against your records before assuming an outage.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.vane.xyz/api/v1/orders/7f9c2e4a-1b3d-4c5e-8f6a-2d9b0c1e3f5a
  ```

  ```typescript TypeScript theme={null}
  const terminal = new Set(["COMPLETED", "ERROR", "TIMED_OUT"]);

  async function track(uuid: string) {
    while (true) {
      const order = await fetch(`https://api.vane.xyz/api/v1/orders/${uuid}`).then((r) => r.json());
      if (terminal.has(order.status)) return order;
      await new Promise((r) => setTimeout(r, 5000));
    }
  }
  ```

  ```python Python theme={null}
  import time, requests

  TERMINAL = {"COMPLETED", "ERROR", "TIMED_OUT"}

  def track(uuid):
      while True:
          order = requests.get(f"https://api.vane.xyz/api/v1/orders/{uuid}").json()
          if order["status"] in TERMINAL:
              return order
          time.sleep(5)
  ```
</CodeGroup>

## SSE

The [status stream](/api-reference/order-status-stream) pushes one `orders:status-update` event per transition. It sends no initial event, so subscribing tells you nothing about where the order stands; fetch the order first, every time. Events carry only `{orderId, status, message, updatedAt}`, with the UUID as `orderId`, which makes each one a cue to re-fetch.

<CodeGroup>
  ```bash cURL theme={null}
  UUID=7f9c2e4a-1b3d-4c5e-8f6a-2d9b0c1e3f5a
  curl -s https://api.vane.xyz/api/v1/orders/$UUID | jq .status   # state first
  # then subscribe; no /v1 in this path. The server closes a silent stream after 60 s, so loop.
  while :; do curl -sN https://api.vane.xyz/api/orders/$UUID/status-stream; sleep 5; done
  ```

  ```typescript TypeScript theme={null}
  const api = "https://api.vane.xyz/api";
  const uuid = "7f9c2e4a-1b3d-4c5e-8f6a-2d9b0c1e3f5a";
  const terminal = new Set(["COMPLETED", "ERROR", "TIMED_OUT"]);
  const get = () => fetch(`${api}/v1/orders/${uuid}`).then((r) => r.json());

  let order = await get(); // state first; the stream won't repeat it
  render(order);

  if (!terminal.has(order.status)) {
    const stream = new EventSource(`${api}/orders/${uuid}/status-stream`); // no /v1
    const sync = async () => {
      order = await get();
      render(order);
      if (terminal.has(order.status)) stream.close();
    };
    stream.onopen = sync; // runs on first connect and after every reconnect
    stream.addEventListener("orders:status-update", sync); // named event, so onmessage never fires
  }
  ```
</CodeGroup>

## Reconnect and fallback

Streams drop, and the server itself closes any stream that has been silent for 60 seconds, so over a 30 minute deposit window you reconnect about 30 times. Reconnect to the same URL and re-fetch the order before trusting new events, because missed transitions are never replayed. `EventSource` reconnects on its own after the 5 second `retry` delay, and putting the re-fetch in `onopen` covers every reconnect in one place. Raw HTTP clients need an explicit loop: reopen the stream whenever it closes, with a read timeout above 60 seconds so the server always closes first. Keep a slow poll running underneath the stream, and shut everything down once a fetch shows a terminal status.
