Core Concepts
Understanding the building blocks of Synento.
Understanding the building blocks of Synento.
Architecture Overview
Synento follows an API-first, agent-native architecture: every feature is exposed through REST endpoints, the dashboard is simply a client of those same APIs, and nothing requires a human in that dashboard to set up — a coding agent can create a project, publish media, and read it back through the same calls.
┌──────────────┐ REST ┌─────────────┐ WebSocket ┌──────────────┐
│ CLI / SDK │ ◄────────► │ Synento │ ◄─────────────►│ WebSocket │
│ Dashboard │ │ Server │ │ Hub │
│ External │ │ (Fastify) │ │ (Hub.ts) │
│ Integrations│ └─────────────┘ └──────────────┘
└──────────────┘ │
Recording
(StreamStore)Hierarchy: Organisation → Project → Session
Organisation
The top-level container representing a team, company, or account. All projects belong to an organisation.
- Created automatically when you register via the dashboard
- Billing applies at the organisation level (free tier: 3,000 participant-minutes and 50 GiB, no card required)
Project
A scoped workspace under an organisation. Each project has:
- Environment (e.g.,
development,staging,production) — optional, for your own organization - API Key (secret key:
sk_live_xxxxx) — used to authenticate all API requests for this project
Projects are the unit of billing. Usage is tracked per project and aggregated to the organisation level for billing purposes.
Session
The core unit of live streaming and recording. Each session:
- Has a unique ID (UUID format)
- Can have multiple participants connected simultaneously via WebSocket
- Is automatically recorded as it happens — no separate recording setup needed (stream-native)
- Is instantly replayable once it ends, using windowed playback API
type Session = {
id: string; // Unique session ID (UUID)
projectId: string; // Parent project
name: string; // Display name (optional)
createdBy: string; // Creator identifier
isPublic?: boolean; // Whether anyone can access this session's replay
startedAt: string | null; // When first participant joined
endedAt: string | null; // When last participant left
createdAt: string; // Creation timestamp
};The Stream-Native Recording Model
This is what makes Synento fundamentally different from traditional video platforms.
Key Principle: Recording = Persisted Stream
There is no separate recording pipeline. When participants stream via WebSocket, every message is immediately persisted to the StreamStore (a multi-stream append log). This same stored data powers both:
- Replay — iterating the stream in chronological (or variable-speed) order
- Export — reading the full stream and encoding it to MP4
Stream Types
Synento persists a layout-agnostic recording: separated media tracks plus a typed event timeline. Presentation (grid, active-speaker, etc.) is resolved at playback time.
| Stream | Purpose | Example |
|---|---|---|
media/{userId}/cam | Camera video per participant | WebCodecs EVC1 or MJPEG bytes |
media/{userId}/mic | Microphone audio per participant | Raw s16le audio |
media/{userId}/screen | Screen share per participant | Same video formats as cam |
events | Structured session timeline | { "v": 1, "type": "speaking.started", "actor": "alice", … } |
director | Computed layout decisions | { "type": "director.cut", "data": { "focus": "bob" } } |
chat | Text messages | { "text": "Hello!", "userId": "u1" } |
captions/{lang} | Caption cues (optional) | { "type": "caption.cue", "data": { "text": "…", "end": … } } |
meta | Legacy join/leave/control | JSON (superseded by events for new integrations) |
Composition Layer
The recording stores what happened; playback decides how to show it:
Tracks + events → Session state → Layout descriptor → Composed view
↑ ↑
director track grid / active-speaker / presenter / …- Client:
@synento/playerCompositor+LayoutEnginedecode visible tracks and draw regions. - Server: FFmpeg export uses the same layout vocabulary (
grid,presenter, orientation). - Manifest:
GET /v1/sessions/:id/manifestindexes tracks, bounds, and capabilities for fast bootstrap.
What This Means for Developers
- No encoding delay — replay is available immediately after a session ends
- Instant layout switching — change grid ↔ active-speaker without re-fetching
- Selective track fetch — manifest-driven bandwidth savings (fetch only visible tracks)
- Windowed reading — large sessions don't need to be loaded entirely
- Variable speed replay — replay at 0.5x, 2x, or any speed using time-based buffering
Access Control Model
Sessions support three levels of access:
| Level | Who Can Access | How |
|---|---|---|
| Private (default) | Only holders of a valid connection token | API key + session ID |
| Public | Anyone with the session URL | No auth required |
| Link-only | Only holders of an expiring replay link | Token in URL (TTL 1 min – 30 days) |
See Access Control Guide for detailed API usage.
Connection Tokens & WebSocket Authentication
Every participant needs a connection token to join or replay a session:
- Request via
POST /v1/sessions/{id}/connectionwith API key auth - Receive an
access_token(JWT) that expires in a configurable time window - Connect to WebSocket:
ws://host/ws?session={sessionId}&access_token={token}&user_id=alice
Tokens include claims for:
user_id— participant identifiersession_id— the session to join- Mode-specific parameters:
replay,from_ts,speedfor replay mode
Usage Tracking & Billing
Usage is tracked per project and aggregated at the organisation level:
- Streaming minutes: calculated from
started_attoended_atper session - Storage bytes: size of exported MP4 files
Billing tiers — the authoritative source is GET /v1/billing/plans:
| Tier | Participant-minutes | Storage | Retention | Cost |
|---|---|---|---|---|
| Free | 3,000 included | 50 GiB | up to 30 days | $0, no card |
| Pro | 4,000 included | 50 GiB | up to 90 days | $19/mo, then $0.004/participant-minute and $0.06/GiB-month |
Two things worth being precise about, because both have caused real errors:
- Usage is metered in participant-minutes, not room-minutes: a four-person call for ten minutes is 40, not 10.
- Storage is GiB (2³⁰ bytes), the unit S2 bills in, and the API fields say
so (
includedStorageGib,storageUsedGib). OnlystorageBytesUsedis bytes. Scaling a GiB figure by 1e9 renders a 50 GiB allowance as "46.57 GB".
Replay API & Windowed Playback
The replay system uses window-based iteration to handle sessions of any size:
GET /v1/sessions/:id/manifest— reconstruction contract (participants, tracks, bounds, capabilities)GET /v1/sessions/:id/playback/timeline— compact metadata (participants, duration, stream ids)GET /v1/sessions/:id/playback?from_ts=0&window_size=30000— read 30-second windows of all tracks + events- Repeat until
next_base_seqis null
Each window returns events from separated media tracks, the events timeline, director track, and chat. The Player SDK composes them into configurable layouts (grid, active-speaker, presenter, screen-share).
See Recordings & Replay Guide for layout descriptors, export parameters, and participant redaction.