This tutorial builds the shape of a real SaaS backend that proxies AI through Roadie (journey J2): your secret key stays on the server, every call is attributed to one of your end users, and you get typed errors, automatic retries, usage, cost, and a gateway requestId on every response. It uses the first-party @roadie/sdk. The finished code mirrors the runnable examples/node-chat reference app, which is exercised against a live gateway in the repo’s CI smoke gate — so what you copy here is proven against the real wire contract.
Prefer to keep your existing OpenAI code? See the OpenAI drop-in tutorial instead. This page adopts the Roadie SDK for its typed errors, retries, and normalized responses.

Prerequisites

In the dashboard:
  1. Create a project (its development and production environments are created for you).
  2. Add and validate a provider credential (OpenAI or Anthropic — BYOK). See Providers & BYOK.
  3. Create a secret key (rd_sk_…) for the environment you want to call.
You will need Node 20+.

1. Scaffold the project

Put your key in a local .env (never commit it):
.env
A secret key grants full access to your project’s data plane. Keep it on the server. The SDK throws if it detects an rd_sk_… key in a browser-like environment — client apps use client tokens via a tokenProvider.

2. Construct the client once

Build the client from the environment and reuse it. Providing baseUrl is optional — omit it for the default hosted gateway ().
src/roadie.ts

3. A non-streaming completion

chat.create returns the normalized response: the assistant message, finish_reason, token usage, an estimated cost, and the gateway requestId. Attribute the call to one of your end users with user so per-user limits, quotas, and analytics apply.
src/chat.ts
model accepts an explicit provider/model id (like openai/gpt-4o) or a project alias (like smart) that fails over across providers — see Models, aliases & fallback.

4. Stream tokens to the caller

Iterate the async-iterable stream with for await. content_delta events carry incremental text; the terminal message_end event carries the final usage. The onDelta callback is where you forward each chunk — to stdout, a WebSocket, or an HTTP ReadableStream.
src/stream.ts
Every call — streaming or not — accepts { signal, timeoutMs }; pass an AbortSignal to cancel. See Streaming.

5. Create embeddings

embeddings.create accepts a string or an array and returns one vector per input, in order.
src/embeddings.ts

6. Handle failures by type

Every SDK failure is a RoadieError subclass carrying a stable code, the requestId, the HTTP status, and — for rate limits — retryAfter. Branch on the class and react appropriately.
src/errors.ts
The SDK already retries transient failures (network errors, 408/429/5xx) before they reach you, honoring Retry-After. So a RateLimitError in your catch means retries were already exhausted. See Errors & retries and the full error reference.

7. Collect feedback on a response

Use the requestId from a completion to record a thumbs-up/down — the same id shows up in your request logs, so feedback and the request line up.
src/feedback.ts

8. Wire it into a server route

The functions above are transport-agnostic. In a Next.js App Router route you bridge the SDK’s stream onto a ReadableStream so the browser reads tokens as they arrive, while the secret key never leaves the server:
app/api/chat/route.ts
See the Next.js quickstart for the matching client page.

What you built

You built a server-side AI backend on @roadie/sdk: a reusable client, non-streaming and streaming chat, embeddings, feedback, and error handling that branches on typed classes — with every call attributed to one of your end users. Your secret key stays server-side, retries and idempotency are automatic, and each response carries the usage, cost, and requestId you need for billing and support.

Next steps

Per-user limits

Turn user: { id } attribution into per-user rate limits and quotas.

Cross-provider fallback

Route model: 'smart' through an alias that fails over across providers.

Observability

Read the usage, cost, and logs these calls produce.

TypeScript SDK reference

The full client surface: options, resources, streaming, and token providers.