Synento docs

API Reference

Complete endpoint documentation for the Synento server API. Base URL: https://api.synento.com

View as Markdown

Complete endpoint documentation for the Synento server API.

Base URL: https://api.synento.com in production, http://localhost:8080 when running the server locally.

Authentication

Most authenticated endpoints accept either:

  • API key — Authorization: Bearer sk_live_xxxxx or X-API-Key: sk_live_xxxxx (required for direct API, CLI, and server-side integrations)
  • Dashboard login session — synento_session HTTP-only cookie set by POST /v1/auth/login (used by the Synento dashboard)

An API key belongs to a project, but acts for its whole organisation on the management routes (projects, keys, webhooks, members). Keep it on your server.

Two narrower credentials exist for agents:

  • Restricted key — Authorization: Bearer rk_live_xxxxx. One project, and accepted only by POST /v1/sessions, POST /v1/projects/{projectId}/sessions, POST /v1/sessions/{sessionId}/connection (live and replay) and GET /v1/sessions/{sessionId}/manifest. Every other route refuses it. This is what an agent writes into your app's environment. Manage them with GET/POST /v1/restricted-keys and DELETE /v1/restricted-keys/{keyId}.
  • Agent token (sat_…) and OAuth access tokens — accepted only by the MCP endpoint at /mcp, never by the REST API. See Connect your agent. Agent tokens, connected OAuth clients and the agent audit log are managed from a signed-in session: /v1/agent-tokens, /v1/oauth/grants, /v1/agent-activity.

Response Format

All JSON responses use a standard envelope:

{ "data": { ... }, "error": null }           // Success
{ "data": null, "error": { "code": "...", "message": "..." } }  // Error

Error codes: BAD_REQUEST (400), NOT_FOUND (404), UNAUTHORIZED (401), FORBIDDEN (403), CONFLICT (409), SERVER_ERROR (500).


Health

Get Health Status

MethodGET
Path/health
AuthNone (public)

Response: plain text ok or error message.


Projects

List Projects

MethodGET
Path/v1/projects
AuthAPI key (scoped to organisation)

Response:

{ "data": [
  { "id": "...", "name": "My App", "org_id": "...", "environment": null, "created_at": "..." }
], "error": null }

Create Project

MethodPOST
Path/v1/projects
AuthAPI key (scoped to organisation)

Request body:

{ "name": "My App", "environment": "production" }

Response (201):

{ "data": { "id": "...", "name": "My App", "org_id": "...", "environment": "production" }, "error": null }

Session Management

Create Session

MethodPOST
Path/v1/projects/:projectId/sessions
AuthAPI key (scoped to project)

Request body:

{ "name": "Morning Standup" }

Response (201):

{ "data": {
  "id": "...", "project_id": "...", "name": "Morning Standup",
  "created_by": "api-key-user",
  "started_at": null, "ended_at": null, "created_at": "..."
}, "error": null }

Billing: New session creation is blocked if free tier limits are exceeded and no active Stripe subscription.

Get Session

MethodGET
Path/v1/projects/:projectId/sessions/:sessionId
AuthAPI key (scoped to project)

Response: single Session object in envelope. 404 if not found or wrong project.

List Sessions

MethodGET
Path/v1/sessions
AuthAPI key (scoped to project)

Returns all sessions for the authenticated project, sorted by created_at DESC. No projectId in the path.

Response:

{ "data": [
  { "id": "...", "project_id": "...", "name": "Session 1", ... },
  { "id": "...", "project_id": "...", "name": "Session 2", ... }
], "error": null }

Set Session Visibility

MethodPUT
Path/v1/sessions/:sessionId/visibility
AuthAPI key (scoped to project)

Request body:

{ "is_public": true }  // or false to make private

Response:

{ "data": true, "error": null }  // updated visibility state

Get Connection Token (Session)

MethodPOST
Path/v1/sessions/:sessionId/connection
AuthAPI key (scoped to project)

Request body:

{ "user_id": "alice",
  "replay": false,      // omit or false for live; true for replay mode
  "from_ts": 0,         // optional: start replay from this timestamp (ms)
  "speed": 1.0,         // optional: replay speed multiplier
  "focus": ""           // optional: focus on specific stream
}

Response (200):

{ "data": {
  "access_token": "...",      // JWT token, short-lived (5 min)
  "expires_in": 300,          // seconds until expiry
  "session": "...",           // session ID
}, "error": null }

Live Streaming (WebSocket)

Connect via WebSocket

MethodGET (upgrade)
Path/ws?session={sessionId}&access_token={token}&user_id=alice
AuthConnection token (JWT) from /connection endpoint

Connects to the live stream. Messages received are JSON events:

{ "type": "message", "stream_type": "media/alice", "timestamp_ms": 1234567, "body": "<base64-jpeg>" }
{ "type": "message", "stream_type": "chat", "timestamp_ms": 1234568, "body": "<base64-json>" }
{ "type": "control", ... }  // join/leave/control signals as meta events

Session Events

Create Session

MethodPOST
Path/v1/sessions
AuthAPI key (project-scoped)

Creates a session for the authenticated project. Same response shape as creating a project-scoped session.

Get Session Timeline

MethodGET
Path/v1/sessions/:sessionId/timeline
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Returns all events in a session's timeline. For large sessions, prefer the windowed playback API below.


Replay & Playback

Get Playback Timeline (Metadata)

MethodGET
Path/v1/sessions/:sessionId/playback/timeline
AuthAPI key (project-scoped) or public session access

Returns compact timeline metadata without loading full event data:

{ "data": {
  "participant_count": 3,
  "stream_ids": ["events", "director", "chat", "media/alice/cam", "media/alice/mic", "media/bob/cam"],
  "total_events_estimated": 15420,
  "min_ts": 1699876000000,
  "max_ts": 1699876300000
}, "error": null }

Get Session Manifest

MethodGET
Path/v1/sessions/:sessionId/manifest
AuthAPI key (project-scoped) or public session access

Returns the layout-agnostic reconstruction contract: participants, separated track index (cam/mic/screen), time bounds, stream paths, and capabilities (separated-tracks, event-timeline, director-track, configurable-layouts, captions when present).

{ "data": {
  "version": 1,
  "session_id": "sess-abc123",
  "epoch": 1699876000000,
  "start_ts": 1699876000000,
  "end_ts": 1699876300000,
  "participants": [
    { "user_id": "alice", "tracks": [
      { "kind": "cam", "stream_id": "a/.../media/alice/cam", "start_ts": 1000, "end_ts": 5000 }
    ]}
  ],
  "streams": { "events": "a/.../events", "chat": "a/.../chat", "director": "a/.../director" },
  "capabilities": ["separated-tracks", "event-timeline", "configurable-layouts"]
}, "error": null }

Public sessions: GET /v1/public/sessions/:sessionId/manifest.

Get Playback Window (Windowed Stream Reading)

MethodGET
Path/v1/sessions/:sessionId/playback?from_ts={ms}&window_size=30000
AuthAPI key (project-scoped) or public session access

Query parameters:

  • from_ts — milliseconds to start reading from (required)
  • window_size — size of window in ms (optional, defaults 30s)

Response:

{ "data": {
  "events": [
    { "seq": 100, "timestamp_ms": 1699876030000, "stream_id": "a/.../media/alice/cam",
      "body_base64": "<base64-payload>" }
  ],
  "base_seq": 100,
  "next_base_seq": null
}, "error": null }

Playback windows include events from all separated media tracks, the events timeline, director track, and chat. Media payloads are raw track bytes (WebCodecs EVC1 or MJPEG); timeline events are JSON in the envelope { v, type, ts, actor, data }.

Get Public Playback (Unauthenticated)

MethodGET
Path/v1/public/sessions/:sessionId/playback?from_ts={ms}&window_size=30000
AuthNone — only works for public sessions (is_public = true)

Same response shape as authenticated playback, but only accessible for public sessions.

Get Public Playback Timeline (Unauthenticated)

MethodGET
Path/v1/public/sessions/:sessionId/playback/timeline
AuthNone — public sessions only

Same response as authenticated timeline, for public sessions.

MethodGET
Path/v1/public/sessions/:sessionId/replay?token={linkToken}&from_ts=0&window_size=30000
AuthNone — replay token required (or public session)

Reads a playback window using an expiring replay link token. Same response shape as public playback.


Export (MP4)

Export is asynchronous. Enqueue a job, poll status, then download the completed MP4.

Send a project API key on every step below.

Enqueue Session Export

MethodGET
Path/v1/sessions/:sessionId/export
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Query parameters (optional):

ParameterValuesDefault
layoutgrid, presentergrid
orientationlandscape (1280×720), vertical (720×1280)landscape
focusParticipant user id (for presenter layout)first participant

Response (202):

{ "data": { "job_id": "550e8400-e29b-41d4-a716-446655440000" }, "error": null }

Returns 503 with USAGE_LIMITS_EXCEEDED when free tier limits are exceeded.

Poll Export Job Status

MethodGET
Path/v1/exports/:jobId
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Response:

{ "data": {
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "room_id": "sess-abc123",
  "download_url": "/v1/exports/550e8400-e29b-41d4-a716-446655440000/download"
}, "error": null }

Status values: queued, processing, completed, failed.

Download Export MP4

MethodGET
Path/v1/exports/:jobId/download
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Response: binary MP4 data when the job is completed.


Participant Redaction

Redact Participant

MethodDELETE
Path/v1/sessions/:sessionId/participants/:userId
AuthAPI key (project-scoped)

Deletes all media track streams for the participant (cam, mic, screen) and appends a participant.redacted event to the timeline. The rest of the session remains intact.

Response:

{ "data": { "redacted": "alice", "deletedStreams": 3 }, "error": null }

Webhooks

List Webhooks

MethodGET
Path/v1/webhooks
AuthAPI key (project-scoped)

Response: array of active webhooks for the project.

{ "data": [
  { "id": "...", "project_id": "...", "url": "https://example.com/hook",
    "events": ["session.created", "session.ended"], "is_active": true }
], "error": null }

Create Webhook

MethodPOST
Path/v1/webhooks
AuthAPI key (project-scoped)

Request body:

{ "url": "https://example.com/hook",
  "events": ["session.created", "session.started", "session.ended"] }

Valid event types: session.created, session.started, session.ended, recording.ready, export.completed

Response (201):

{ "data": { "id": "...", "project_id": "...", "url": "...",
  "events": ["session.created"], "is_active": true }, "error": null }

Usage & Billing

Get Usage Records

MethodGET
Path/v1/projects/:projectId/usage (project-scoped) or /v1/usage
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Response:

{ "data": {
  "summary": { "streaming_minutes_total": 125.3, "storage_bytes_total": 524288000 },
  "records": [
    { "id": "...", "project_id": "...", "session_id": "...",
      "usage_type": "streaming_minutes", "value": 125.3,
      "recorded_at": "..." }
  ]
}, "error": null }

Get Billing Summary

MethodGET
Path/v1/billing/summary
AuthAPI key (project-scoped) — no projectId in path required

Response:

{ "data": {
  "streaming_minutes_used": 125.3,
  "storage_bytes_used": 524288000,
  "cost_breakdown": {
    "streaming_cost": 12.53,
    "storage_cost": 0.03,
    "total_due": 12.56
  }
}, "error": null }

Get Billing Limits

MethodGET
Path/v1/billing/limits
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Response:

{ "data": {
  "within_free_tier": true,
  "streaming_minutes_used": 125.3,
  "storage_bytes_used_gb": 0.5,
  "has_active_subscription": false,
  "is_blocked": false,
  "status_message": ""
}, "error": null }

Create Stripe Billing Portal Session (Project-scoped)

MethodPOST
Path/v1/projects/:projectId/billing/portal
AuthAPI key (project-scoped) or dashboard login session (synento_session cookie)

Returns a Stripe billing portal URL. Response includes portal_url for redirecting the user to manage their subscription.

Create Stripe Billing Portal Session (Org-scoped)

MethodPOST
Path/v1/billing/portal
AuthAPI key (project-scoped) — no projectId needed

Same as above but uses organisation-level Stripe customer. Recommended for dashboards (no projectId required).


API Key Management

List API Keys

MethodGET
Path/v1/api-keys
AuthAPI key (project-scoped) — no projectId needed in path

Returns metadata for keys belonging to the authenticated project. Secrets are not included (only ID and creation date).

Response:

{ "data": [
  { "id": "...", "project_id": "...", "created_at": "..." }
], "error": null }

Create API Key

MethodPOST
Path/v1/projects/:projectId/api-keys
AuthAPI key (project-scoped)

Response (201): returns the new key's ID and raw secret (sk_live_...). The secret is shown only once — store it securely.

Delete API Key

MethodDELETE
Path/v1/api-keys/:keyId
AuthAPI key (project-scoped) — no projectId needed in path

Response: success confirmation. The deleted key is immediately invalidated.


Authentication & User Management (Email/Password)

Register

MethodPOST
Path/v1/auth/register
AuthNone (public)

Request body: {"email": "user@example.com", "password": "secret123"}

Response (201): creates user + organisation + project, sets session cookie.

{ "data": { "id": "...", "email": "user@example.com", ... }, "error": null }

Login

MethodPOST
Path/v1/auth/login

Request body: {"email": "user@example.com", "password": "secret123"}

Response (200): sets session cookie (synento_session). Session expires in 7 days.

Logout

MethodPOST
Path/v1/auth/logout

Response (200): clears session cookie.

Get Current User

MethodGET
Path/v1/me

Response (200): returns current authenticated user data.

{ "data": { "id": "...", "email": "user@example.com" }, "error": null }

Organisation Membership (Invitations)

Send Invitation to Project's Organisation

MethodPOST
Path/v1/projects/:projectId/invitations
AuthAPI key (project-scoped)

Request body: {"email": "new@example.com", "role": "member"}

Response (201):

{ "data": { "id": "...", "org_id": "...", "email": "new@example.com",
  "role": "member", "created_by": "...", "accepted_at": null }, "error": null }

Redeem Invitation Token

MethodPOST
Path/v1/invitations/redeem

Request body: {"token": "invite-token-xyz"}

Auth: session cookie (user must be logged in). Updates the user's org_id and role.

Response (200): success confirmation with updated org membership.


Public Session Catalog

List Public Sessions

MethodGET
Path/v1/public/sessions
AuthNone (public)

Returns all sessions with is_public = true, sorted by creation date DESC. No project IDs exposed for privacy.

Response:

{ "data": [
  { "id": "...", "name": "Public Demo", "created_at": "...",
    "started_at": "...", "ended_at": "..." }
], "error": null }

MethodPOST
Path/v1/sessions/:sessionId/replay-links
AuthAPI key (project-scoped)

Request body: {"expires_in_minutes": 60} (optional, defaults to a reasonable TTL)

Response (201):

{ "data": {
  "link": "https://host/v1/public/sessions/{sessionId}/replay?token={token}",
  "token": "...",
  "expires_at": "..."
}, "error": null }

The replay link provides unauthenticated windowed playback access until it expires (max 30 days = 43200 minutes).

On this page