Getting Started
Get from zero to your first live video stream in under 5 minutes.
Get from zero to your first live video stream in under 5 minutes.
Using a coding agent? Connect it to Synento over MCP and it can do all of this for you — including proving the video works. See Connect your agent.
Prerequisites
- A Synento account (sign up free: 3,000 participant-minutes a month, no card)
- A server-side key — an
sk_live_API key from the dashboard or CLI, or anrk_live_restricted key (one project; enough for everything on this page)
Option A: Use the SDK (Recommended)
1. Install the packages
npm install @synento/node # server-side: create sessions, mint tokens
npm install @synento/client # browser: publish and receive live audio/videoReact applications can use @synento/react for hooks and
components, and @synento/player for embedded
replay.
2. Mint connection tokens on your server
Your API key is a server-side secret. It never goes to the browser. Instead, your backend exposes one small route that creates a session and mints a short-lived connection token for the user asking to join.
// app/api/synento/route.ts (Next.js App Router)
import { createSynentoClient, resolveWsUrl } from "@synento/node";
// Reads SYNENTO_API_KEY and SYNENTO_API_URL from the environment.
const synento = createSynentoClient();
export const dynamic = "force-dynamic"; // or the route is cached and serves a stale token
export async function POST(request: Request) {
const { sessionId, userId } = await request.json();
const token = await synento.createConnectionToken(sessionId, { userId });
return Response.json({
token: token.accessToken,
wsUrl: resolveWsUrl({
apiBaseUrl: process.env.SYNENTO_API_URL ?? "https://api.synento.com",
requestOrigin: request.headers.get("origin"),
sessionId,
userId,
}),
});
}Use resolveWsUrl rather than assembling the URL yourself — it handles the
loopback-hostname case that otherwise makes local development fail in a way
that produces no error at all, just a call that never connects.
3. Join from the browser
import { SynentoRoom } from "@synento/client";
const room = new SynentoRoom({
userId: "alice",
// Re-invoked on every reconnect, so tokens rotate automatically.
getToken: async () => {
const res = await fetch("/api/synento", {
body: JSON.stringify({ sessionId, userId: "alice" }),
method: "POST",
});
return res.json(); // { wsUrl, token }
},
});
room.on("participantsChanged", (ids) => console.log("in the room:", ids));
await room.connect();
// Publish. The second argument is optional — pass your local preview element
// if you have one. A stream with no video tracks publishes audio only.
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
await room.publishCamera(stream, previewVideoEl);Media travels as binary frames, not JSON — @synento/client handles the
framing, decoding and reconnection. Do not open a raw WebSocket and try to
JSON.parse messages off it.
Recording needs no code. The session's durable streams are the recording, so there is no start-recording call and no recording flag.
4. See it running
demo.synento.com is a two-way call built on exactly these packages. Open it in two tabs, join the same session, then leave and replay it: the recording exists the moment the call does.
Option B: Use HTTP API Directly (cURL)
1. Create a project
curl -X POST https://api.synento.com/v1/projects \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "My Project"}'2. Create a session
curl -X POST https://api.synento.com/v1/projects/{projectId}/sessions \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "Demo Session"}'3. Get a connection token
curl -X POST https://api.synento.com/v1/sessions/{sessionId}/connection \
-H "Authorization: Bearer sk_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{"user_id": "viewer-1"}'4. Connect to WebSocket streaming
Once you have the access_token from step 3, open a WebSocket. Prefer sending
the token as a subprotocol, so it stays out of URLs and access logs:
wss://api.synento.com/ws?session={sessionId}&user_id=viewer-1
Sec-WebSocket-Protocol: synento.v1, synento.token.{accessToken}The query-string form (&access_token=...) is still accepted, but logs the
token.
What travels over that socket is binary, in a self-describing frame format
— not JSON. Unless you are implementing a client from scratch, use
@synento/client, which handles framing, codec
negotiation, decoding, backpressure and reconnection.
Option C: Use the CLI
# Login with your API key
npx synento login sk_live_xxxxx
# Create a project (interactive or with name argument)
npx synento create-project "My Project"
# Create a session (requires project ID)
npx synento create-session "Demo Session" -p {projectId}Option D: Let your coding agent do it
Connect your agent to Synento's MCP server and ask it to add video to your app:
claude mcp add --transport http synento https://api.synento.com/mcpIt mints a restricted key for your .env, writes the server route and the
browser code above, and then checks the recording with verify_session to
confirm camera and microphone actually arrived. See
Connect your agent for other clients and what you approve.
Next Steps
- Read Core Concepts to understand the architecture
- Browse the full API Reference
- Try the copy-paste examples in examples/
- Set up webhooks for event-driven workflows — Webhooks Guide
Environment Variables
| Variable | Description | Default |
|---|---|---|
SYNENTO_API_KEY | Secret key. Server-side only — never expose it to a browser. | — |
SYNENTO_API_URL | Base URL of the Synento API. | https://api.synento.com |
Both are read automatically by createSynentoClient() when you pass no
arguments.
Troubleshooting
"Connection refused" on WebSocket
- If you set
SYNENTO_API_URL, check it ishttps://api.synento.com - Check that the connection token has not expired
"401 Unauthorized" on API calls
- Verify your API key starts with
sk_ - Check that the Authorization header uses
Bearer <key>(no space before the key)
Sessions not appearing in replay
- Ensure the session has ended (replay reads completed sessions)
- Check that events were actually sent during the stream