Quickstart
Get from zero to a live avatar session in five minutes — create the session, connect the stream, end it.
Create and start a live avatar session in one API call, connect your frontend
to the media stream, and end the session from your backend. Everything below uses
the six canonical /v1/ endpoints — you can copy-paste the whole flow.
Base URL
All examples use the placeholder below. Replace it with your assigned API host.
https://<orvyn-public-api-host>
The 60-second path
Create and start a session
One call creates the session, starts rendering, and returns a short-lived client token.
Connect the WebSocket
Open the ws_url from the session response — the token is already embedded.
Receive `session.ready` + media
The server sends session.ready, then fMP4 init and media segments.
End the session
Clean up from your backend to release GPU resources.
Step 1 — Create and start a session
The session must specify exactly one provider_type and a matching
provider_config. Provider credentials are ephemeral — your backend mints a
fresh token for every session and Orvyn holds it in memory only for the session
lifetime. Never send provider credentials to the frontend.
curl -X POST "https://<orvyn-public-api-host>/v1/sessions" \
-H "Authorization: Bearer $AVTR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider_type": "openai_realtime",
"provider_config": {
"openai_realtime": { "client_secret": "<ephemeral-client-secret>" }
}
}'const response = await fetch("https://<orvyn-public-api-host>/v1/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AVTR_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
provider_type: "openai_realtime",
provider_config: {
openai_realtime: { client_secret: "<ephemeral-client-secret>" },
},
}),
});
const { data } = await response.json();import os
import requests
response = requests.post(
"https://<orvyn-public-api-host>/v1/sessions",
headers={
"Authorization": f"Bearer {os.environ['AVTR_API_KEY']}",
"Content-Type": "application/json",
},
json={
"provider_type": "openai_realtime",
"provider_config": {
"openai_realtime": {"client_secret": "<ephemeral-client-secret>"}
},
},
)
data = response.json()["data"]A successful response returns the session id, the stream metadata, and the
short-lived client_token-backed WebSocket URL:
{
"success": true,
"data": {
"session_id": "session:8f3c1a2b-...",
"status": "created",
"stream": {
"transport": "websocket_fmp4",
"ws_url": "wss://<orvyn-public-api-host>/v1/sessions/session:.../ws?token=eyJ...",
"token_expires_at": 1718352300000
}
},
"timings": { "latency_ms": 9 }
}
Save the session_id — you need it for cleanup. Treat the full ws_url as a
bearer credential (see the security note below).
Step 2 — Connect the WebSocket
POST /v1/sessions already created AND started the session — there is no
separate start step. Open the ws_url exactly as returned; the token is already
embedded, so do not add auth headers.
const ws = new WebSocket(wsUrl);
ws.binaryType = "arraybuffer";
ws.onopen = () => {
// No session.start needed — POST /v1/sessions already started the session.
};
ws.onmessage = (event) => {
if (typeof event.data !== "string") return; // binary audio frames
const msg = JSON.parse(event.data);
switch (msg.type) {
case "session.ready":
console.log("Avatar ready:", msg.avatarId);
break;
case "avatar.fmp4.init":
console.log("fMP4 init segment received");
break;
case "avatar.fmp4.segment":
console.log("Media segment", msg.sequence);
break;
case "session.ended":
console.log("Session ended");
break;
case "error":
console.error("Server error:", msg.code, msg.message);
break;
}
};
The full message catalog — lifecycle, fMP4 media, and speech pipeline messages — is documented in the WebSocket guide.
Step 3 — End the session
Always end the session from your backend to release resources:
curl -X POST "https://<orvyn-public-api-host>/v1/sessions/$SESSION_ID/end" \
-H "Authorization: Bearer $AVTR_API_KEY"await fetch(
`https://<orvyn-public-api-host>/v1/sessions/${sessionId}/end`,
{
method: "POST",
headers: { Authorization: `Bearer ${process.env.AVTR_API_KEY}` },
},
);requests.post(
f"https://<orvyn-public-api-host>/v1/sessions/{session_id}/end",
headers={"Authorization": f"Bearer {os.environ['AVTR_API_KEY']}"},
)Refreshing the client token
The token in ws_url expires after 5 minutes. To reconnect after expiry
(network drop, browser sleep), mint a fresh one:
curl -X POST \
"https://<orvyn-public-api-host>/v1/sessions/$SESSION_ID/client-token" \
-H "Authorization: Bearer $AVTR_API_KEY"
{
"success": true,
"data": {
"ws_url": "wss://<orvyn-public-api-host>/v1/sessions/session:.../ws?token=eyJ...",
"token_expires_at": 1718352600000
},
"timings": { "latency_ms": 3 }
}
Use the newest ws_url for reconnects. Refreshing does not revoke previously
issued tokens — they remain valid until their own expiry.
Handle the ws_url safely
The ?token= query parameter is a short-lived bearer credential (5-minute
TTL). Anyone holding the URL can connect to the session’s WebSocket.
- Do use the
ws_urlas-is to open the connection. - Do not log it, screenshot it, or store it in analytics or browser history.
- Do call
POST /v1/sessions/{session_id}/client-tokenfor reconnects after expiry.