API Reference

SSE (Server-Sent Events) API

Stream real-time events to browsers and HTTP clients using Server-Sent Events with token-based authentication.

The SSE API provides a persistent HTTP streaming connection for receiving real-time events. Clients create a stream token with one or more subscriptions, then connect using the native EventSource API or any HTTP client that supports streaming responses.

Info

SSE is ideal for browser dashboards, monitoring tools, and any client that only needs to receive events. Unlike WebSocket (bidirectional), SSE is server-to-client only but works with standard HTTP — no special proxy configuration required.

Concepts

  • Stream Token — A time-limited credential (sst_*) that grants access to a specific set of event subscriptions. Created via API, used as a query parameter to connect.
  • Subscription — A filter within a token that defines which events to receive. Supports event type patterns and payload filters.
  • Replay Buffer — A per-token event history stored in Redis. When a client reconnects with Last-Event-ID, missed events are replayed automatically.
  • Cross-Instance Delivery — Events are delivered to SSE clients regardless of which backend instance they're connected to, using Redis Pub/Sub. No sticky sessions required.

Create a Stream Token

POST /api/sse/token

Creates a token with one or more event subscriptions.

Request Body:

FieldRequiredDescription
ttlMinutesYesToken lifetime in minutes (5–60)
subscriptionsYesArray of subscription objects
subscriptions[].eventsYesEvent type patterns (e.g. ["session.status", "annotation.*"])
subscriptions[].filterNoPayload filter for this subscription
bufferSizeNoReplay buffer size (default 1000, max 5000)

Example:

curl -X POST /api/sse/token \
  -H "Content-Type: application/json" \
  -H "X-Application-Id: app_abc123" \
  -H "X-Environment: production" \
  -d '{
    "ttlMinutes": 30,
    "subscriptions": [
      { "events": ["session.status", "session.closed"], "filter": { "installSid": "AI4b56b78..." } },
      { "events": ["annotation.*"] }
    ],
    "bufferSize": 2000
  }'

Response (201):

{
  "streamToken": "sst_a1b2c3d4e5f6...",
  "tokenId": "stk_xyz789",
  "expiresAt": "2026-06-27T00:27:00.000Z",
  "subscriptions": [
    { "id": "ssub_001", "events": ["session.status", "session.closed"], "filter": { "installSid": "AI4b56b78..." } },
    { "id": "ssub_002", "events": ["annotation.*"] }
  ],
  "bufferSize": 2000
}

Connect to Stream

GET /api/sse/stream?token=sst_a1b2c3d4e5f6...

Opens a persistent SSE connection. Events matching any of the token's subscriptions are pushed to the client.

Query Parameters:

ParameterRequiredDescription
tokenYesThe stream token from token creation
lastEventIdNoResume from this event ID (alternative to Last-Event-ID header)

Headers:

HeaderDescription
Last-Event-IDStandard SSE reconnection header — resumes from this ID

Example (browser):

const stream = new EventSource('/api/sse/stream?token=sst_a1b2c3d4e5f6...');

stream.addEventListener('session.status', (e) => {
  const event = JSON.parse(e.data);
  console.log('Session status:', event);
  // { subscriptionId: "ssub_001", sid: "ES123", status: "Open", ... }
});

stream.addEventListener('annotation.created', (e) => {
  const event = JSON.parse(e.data);
  console.log('Annotation:', event);
});

// System events
stream.addEventListener('token_expiring', (e) => {
  console.warn('Token expiring soon, extend it!');
  // Call /api/sse/token/extend
});

stream.addEventListener('token_expired', () => {
  stream.close();
});

Example (curl):

curl -N "https://api.example.com/api/sse/stream?token=sst_a1b2c3d4e5f6..."

SSE Frame Format:

id: evt_abc123
event: session.status
data: {"subscriptionId":"ssub_001","sid":"ES123","status":"Open","installSid":"AI4b56b78..."}

System Events:

EventWhenData
token_expiring30 seconds before token expires{ "expiresAt": "...", "message": "..." }
token_expiredToken has expired{ "message": "Stream token expired" }
token_extendedToken TTL was extended{ "expiresAt": "..." }
token_revokedToken was explicitly revoked{ "message": "Token has been revoked" }
server_shutdownServer is shutting down{ "message": "Server shutting down" }

Heartbeat: A :heartbeat comment is sent every 15 seconds to keep the connection alive through proxies and load balancers.

Extend a Token

POST /api/sse/token/extend

Extends the TTL of an existing token without disconnecting the stream. Can also add or remove subscriptions.

Request Body:

FieldRequiredDescription
tokenYesThe raw stream token to extend
ttlMinutesYesNew TTL from now (5–60 minutes)
addSubscriptionsNoAdditional subscriptions to add
removeSubscriptionsNoSubscription IDs to remove

Example:

curl -X POST /api/sse/token/extend \
  -H "Content-Type: application/json" \
  -d '{
    "token": "sst_a1b2c3d4e5f6...",
    "ttlMinutes": 30,
    "addSubscriptions": [
      { "events": ["exam.*"] }
    ],
    "removeSubscriptions": ["ssub_002"]
  }'

Response (200):

{
  "tokenId": "stk_xyz789",
  "expiresAt": "2026-06-27T00:57:00.000Z",
  "subscriptions": [
    { "id": "ssub_001", "events": ["session.status", "session.closed"], "filter": { "installSid": "AI4b56b78..." } },
    { "id": "ssub_003", "events": ["exam.*"] }
  ],
  "bufferSize": 2000
}

Connected clients automatically receive a token_extended event on their stream.

Revoke a Token

DELETE /api/sse/token/:tokenId

Immediately revokes a token. Any connected clients using this token receive a token_revoked event and are disconnected.

Example:

curl -X DELETE /api/sse/token/stk_xyz789

List Active Connections

GET /api/sse/connections

Returns all active SSE connections on this instance.

Response:

{
  "connections": [
    {
      "id": "sse_abc123",
      "tokenId": "stk_xyz789",
      "connectedAt": 1719446820000,
      "eventsDelivered": 42,
      "lastEventId": "evt_def456"
    }
  ],
  "total": 1
}

Event Matching

SSE subscriptions use the same matching logic as webhooks and WebSocket subscriptions:

Event Type Patterns:

PatternMatches
session.statusExactly session.status
session.*Any event starting with session.
*All events

Payload Filters (AND logic):

{
  "filter": {
    "installSid": "AI4b56b78...",
    "status": "Open"
  }
}

An event matches only if ALL filter conditions are satisfied.

Replay on Reconnect

When a client reconnects (browser auto-reconnect, network blip), events missed during disconnection are replayed from the Redis-backed buffer:

  1. Client disconnects
  2. Events continue flowing into the replay buffer (up to bufferSize events per token)
  3. Client reconnects with Last-Event-ID header (sent automatically by EventSource)
  4. Server replays all events after that ID, then continues live streaming

The replay buffer TTL matches the token TTL — once the token expires, the buffer is cleared.

Security

  • Token scoping — Each token is scoped to a specific application and environment. Events from other apps/environments are never delivered.
  • Token hashing — Tokens are stored as SHA-256 hashes in Redis. The raw token is only returned once on creation.
  • TTL enforcement — Tokens automatically expire. The server closes connections for expired tokens and cleans up resources.
  • Rate limiting — The /api/sse/token endpoint is subject to the standard API rate limiter.

Horizontal Scaling

SSE works across multiple backend instances without sticky sessions:

  1. CDC leader dispatches event → publishes to Redis Pub/Sub channel
  2. All instances receive the event via their Pub/Sub subscription
  3. Each instance checks its local SSE clients for matching subscriptions
  4. Matching clients receive the event regardless of which instance they're connected to

This means you can scale horizontally behind a standard round-robin load balancer.