LayerHopDocsLaunch app (opens in a new tab)

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.

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 order with an OrderSummary filled, refunded, failed or expired
GET /v1/checkout/sessions/{id}/events session with a CheckoutSession paid, expired or needs_review
GET /v1/webhooks/stream (API key) event with a webhook payload Never (see the CLI)

Orders are tracked once their transaction is reported with POST /v1/orders/{quoteId}/submitted (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#

Terminal
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#

TypeScript
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 LayerHopApiErrors, 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:

JavaScript
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 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 uses it to forward events to your laptop, so you can develop a webhook handler without a public URL:

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

See Webhooks → Test locally with the CLI.

Last updated