Web SDK quickstart
Drive the whole avatar session from the browser with @avtr/web-sdk — session lifecycle, token handling, and error semantics in one client.
The browser SDK packages the canonical /v1/ flow — create, connect, refresh,
status, end — behind one client, so your frontend never hand-rolls REST calls
or token logic. The SDK is bound to the same generated contract as this site:
it never invents endpoints, fields, or error codes.
Install and construct
npm install @avtr/web-sdk
import { AvtrWebSdk } from "@avtr/web-sdk";
const sdk = new AvtrWebSdk({
apiBaseUrl: "https://<orvyn-public-api-host>", // REST base (no trailing slash needed)
wsBaseUrl: "wss://<orvyn-public-api-host>", // optional; derived from apiBaseUrl when omitted
videoElement: document.querySelector("video"),
apiKey: "<server-minted-key>", // only needed for SDK-initiated REST calls
sessionConfig: {
/* CreateSessionRequest body when the SDK creates the session */
},
diagnostic: (message) => console.log(message),
});
| Option | Purpose |
|---|---|
apiBaseUrl |
REST base URL for the /v1/ control plane |
wsBaseUrl |
Media WebSocket base; derived from apiBaseUrl when omitted |
videoElement |
<video> element the bundled MSE player renders into |
apiKey |
API key — only needed when the SDK itself makes REST calls |
sessionConfig |
CreateSessionRequest body used when the SDK creates the session |
diagnostic |
Diagnostic log callback |
Session lifecycle methods
| Method | Contract | Semantics |
|---|---|---|
createSession(apiBaseUrl, auth, body) |
POST /v1/sessions |
Returns the bare SessionResponse — client_token is delivered here exactly once |
sdk.connect(sessionId, clientToken?) |
Media WebSocket /v1/sessions/{session_id}/ws?token= |
Refreshes an expired token before connecting; on a pre-open failure with 401 semantics it performs exactly one refresh + one retry. Mic capture starts automatically |
sdk.refreshNow() |
POST /v1/sessions/{session_id}/client-token |
Explicit refresh; returns the bare ClientTokenResponse (5-minute TTL). Single-flight — concurrent callers share one request |
sdk.status() |
GET /v1/sessions/{session_id} |
Returns the bare SessionStatusResponse. Never contains a client_token |
sdk.endSession({ force? }) |
POST /v1/sessions/{session_id}/end |
Returns the bare EndSessionResponse; force: true appends ?force=true to skip the graceful handshake |
sdk.disconnect() |
— | Local teardown only; no REST call |
Token lifecycle
The client_token is a short-lived bearer credential with a 5-minute TTL
(expires_at is epoch milliseconds). The SDK tracks the newest token and
handles four refresh triggers:
- Creation —
createSession()returns the first token in theSessionResponse. - Expiry-triggered — before opening the socket, a cached token whose
expires_athas passed is refreshed via the client-token endpoint (single-flight, lazy — no timers). - 401-triggered — the media WebSocket answers an expired or invalid
?token=with HTTP 401. A pre-open connect failure while a token is known triggers exactly one refresh and one retry; a second failure propagates the original error. - Manual —
await sdk.refreshNow()for reconnects, delayed connections, and browser sleep recovery.
Refreshing does not revoke previously issued tokens — outstanding tokens simply age out at their own expiry (5-minute TTL).
End semantics — the 409 resolution
POST /end returns 409 when the session is not active:
AVTR_SESSION_ENDED— status wasended/ended_with_warnings.AVTR_SESSION_CONFLICT— status wascreated/ending/failed.
Both mean the end intent can no longer change the outcome, so the SDK resolves
them to { sessionId, status: "ended", endedAt: 0 } instead of throwing
(endedAt: 0 marks “already ended; server timestamp not re-issued”). All other
errors — 401, 403, 404, 429, 503 — throw AvtrApiError. See the
lifecycle guide for the full
matrix.
Error handling
REST failures throw AvtrApiError, which carries the flat contract error
fields:
| Property | Meaning |
|---|---|
code |
The AVTR_* error code from the flat error shape |
status |
HTTP status code |
requestId |
The request_id correlation UUID |
retryAfter |
retry_after in seconds — present on retryable codes only |
docUrl |
The doc_url documentation link |
try {
await sdk.endSession({ force: true });
} catch (err) {
console.error(err.code, err.status, err.requestId, err.retryAfter);
}
Match on code (and status), never on message — see
errors, limits & security for the full
catalog and the retry rules.
Media playback
The SDK bundles an MSE player (MediaSource + SourceBuffer, bounded segment
queue with backpressure handling) that renders fMP4 segments into your
videoElement. For the underlying media protocol — segments, microphone PCM
frames, and the message catalog — see the
WebSocket & fMP4 guide, including its
MSE playback section.