# Live order status

> Get order and checkout updates the moment they happen with Server-Sent Events. Stream GET /v1/orders/{quoteId}/events or GET /v1/checkout/sessions/{id}/events from a browser, a server or curl, or use lh.streamOrder and the useOrderStream React hook.

Source: https://docs.layerhop.com/guides/live-status

LayerHop pushes order and checkout updates to you as they happen, over **Server-Sent Events** (SSE): one long-lived HTTP response that sends a new event on every change. You get the current state right away, then each change within about a second of LayerHop seeing it, and the stream closes by itself when the order is final. No polling loop, no webhook server needed.

| Stream | Events | Ends when |
|---|---|---|
| [`GET /v1/orders/{quoteId}/events`](/api-reference#stream-an-orders-status) | `order` with an [`OrderSummary`](/api-reference#ordersummary) | `filled`, `refunded`, `failed` or `expired` |
| [`GET /v1/checkout/sessions/{id}/events`](/api-reference#stream-a-checkout-session) | `session` with a [`CheckoutSession`](/api-reference#checkoutsession) | `paid`, `expired` or `needs_review` |
| [`GET /v1/webhooks/stream`](/api-reference#stream-your-webhook-events) (API key) | `event` with a webhook payload | Never (see [the CLI](#test-webhooks-locally)) |

Orders are tracked once their transaction is reported with [`POST /v1/orders/{quoteId}/submitted`](/api-reference#report-the-broadcast-transaction) (the SDK's `reportSubmitted`). While a transaction is in flight LayerHop checks it every 5 seconds for the first half minute, then backs off.

## Try it with curl

```bash
curl -N https://api.layerhop.com/v1/orders/q_6f1c2d0e-8a51-4c1e-9d0b-2f7a9e3c4b10/events
```

```text
event: ready
data: {"retryMs":3000}

event: order
data: {"quoteId":"q_6f1c…","status":"submitted","provider":"relay",…}

event: order
data: {"quoteId":"q_6f1c…","status":"pending",…}

event: order
data: {"quoteId":"q_6f1c…","status":"filled","dstTxHash":"5VER…",…}
```

Lines starting with `:` are keep-alive pings, sent every 15 seconds.

## TypeScript SDK

```ts
import { LayerHop } from "@layerhop/sdk";

const lh = new LayerHop();
await lh.reportSubmitted(quoteId, txHash);

for await (const order of lh.streamOrder(quoteId)) {
  console.log(order.status); // submitted → pending → filled
}

// Checkout sessions
for await (const session of lh.checkout.stream(sessionId)) {
  if (session.status === "paid") fulfil(session);
}
```

Pass `{ signal }` (an `AbortSignal`) to stop early. Errors are `LayerHopApiError`s, like every other SDK call.

## React

```tsx
import { useOrderStream } from "@layerhop/react";

function OrderProgress({ quoteId }: { quoteId: string }) {
  const { order, isFinal, connected, error } = useOrderStream(quoteId);
  if (!order) return <p>Connecting…</p>;
  return <p>{order.status}{!isFinal && connected ? " (live)" : ""}</p>;
}
```

`useOrderStream` reconnects after network errors (1 s, 2 s, 4 s, up to 30 s) and stops once the order is final. It needs `@layerhop/sdk` 0.3 or later.

## In the browser without the SDK

`EventSource` works directly:

```js
const es = new EventSource(`https://api.layerhop.com/v1/orders/${quoteId}/events`);
es.addEventListener("order", (e) => {
  const order = JSON.parse(e.data);
  render(order);
  if (["filled", "refunded", "failed", "expired"].includes(order.status)) es.close();
});
```

`EventSource` cannot send headers, so it is anonymous; order and session streams don't need a key. Browsers reconnect it automatically: close it yourself once the order is final.

## Limits

- A stream lasts at most **30 minutes**; reconnect if you need longer. You always get the current state first, so nothing is missed.
- At most **20 open streams** per API key, or per IP without a key (`RATE_LIMITED` beyond that).
- Anyone who knows a `quoteId` or session id can watch it. The streams show the same fields as the public `GET` endpoints (no account ids, no merchant `reference` or `metadata`).

## Webhooks or streams?

Use **streams** to show progress to a user while they wait (a swap screen, a checkout page). Use **[webhooks](/guides/webhooks)** for your backend: they are signed, retried for 24 hours and arrive even when nobody is watching. Many apps use both.

## Test webhooks locally

`GET /v1/webhooks/stream` streams every webhook event of your account, in your API key's mode. The [CLI](/cli) uses it to forward events to your laptop, so you can develop a webhook handler without a public URL:

```bash
LAYERHOP_API_KEY=lh_test_… npx @layerhop/cli listen --forward-to http://localhost:3000/webhooks
```

See [Webhooks → Test locally with the CLI](/guides/webhooks#test-locally-with-the-cli).
