Skip to content
torqee Developers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Realtime Events

Subscribe to workspace events with Server-Sent Events.

Realtime events are delivered from:

GET https://connect.torqee.app/api/v1/events/stream

The response is text/event-stream. Each event has event: <type> and JSON data matching the WorkspaceEvent schema in the OpenAPI spec.

Event types

Event type Required scope
session.created torqee:sessions:read
session.status_changed torqee:sessions:read
transcript.segment.created torqee:transcripts:read

When filters is omitted, Connect subscribes to lifecycle events (session.created and session.status_changed) and filters them by the scopes the credential already has.

Filters

The filters query parameter is a URL-encoded JSON array. Entries are OR-matched. Each entry has a type and an optional sessionId. For transcript.segment.created, omit sessionId to receive segments from every session in the workspace, including sessions that start after you connect. Include sessionId to subscribe to just that session.

[
  { "type": "session.created" },
  { "type": "session.status_changed" },
  { "type": "transcript.segment.created", "sessionId": "session_123" }
]

To subscribe to lifecycle events and all transcripts in one connection:

[
  { "type": "session.created" },
  { "type": "session.status_changed" },
  { "type": "transcript.segment.created" }
]
curl -N "https://connect.torqee.app/api/v1/events/stream?filters=%5B%7B%22type%22%3A%22session.created%22%7D%5D" \
  -H "Authorization: Bearer torqee_YOUR_API_KEY"

Browser EventSource cannot set an Authorization header directly. Use an SSE client that supports headers, or stream the response with fetch:

const response = await fetch(
  "https://connect.torqee.app/api/v1/events/stream",
  {
    headers: { Authorization: "Bearer torqee_YOUR_API_KEY" },
  },
);

const reader = response.body?.getReader();

Cost and limits

Filters are limited to 20 entries. Each entry costs 10, and the current budget is 100. Requests above the budget return:

{
  "error": "filter_cost_exceeded",
  "cost": 110,
  "budget": 100,
  "entries": [
    { "type": "session.created", "cost": 10 },
    { "type": "session.status_changed", "cost": 10 }
  ]
}

Too many concurrent streams for the same workspace return:

{ "error": "connection_limit" }

Event delivery is best-effort. Events emitted while the client is disconnected are not replayed. Reconnect with backoff and reconcile missed state through the REST API.

Detecting missed segments

transcript.segment.created data includes sessionCommittedIndex, the same index exposed by REST for committed segments. It starts at 0 and increases by 1 in commit order within each session, across recording executions. Delivery is best-effort, so received indices can have gaps, and the same segment can occasionally arrive more than once.

Track the last applied index separately for each session, starting at -1:

  1. If an event’s index is less than or equal to the last applied index, discard it as already applied. This also removes duplicate deliveries.
  2. If the index is exactly the last applied index plus 1, apply the segment and update the last applied index.
  3. If the index is higher, fetch GET /api/v1/sessions/{sessionId}/transcripts?revisionKind=committed from Connect. Apply the committed segments in sessionCommittedIndex order through the last index in the response, then resume processing events. Buffer events for that session while fetching and process them with the same rules after reconciliation, discarding any segments already applied via REST.

These rules also detect missing history when the first received index is not 0. If an event has no sessionCommittedIndex, reconcile through the same REST endpoint. The field is optional during the publisher rollout.

Do not use sequence to detect missed segments: it restarts for each recording execution and can overlap within a session. Always reconcile through REST after reconnecting, since disconnected events are not replayed.

Payload example

{
  "type": "session.created",
  "sessionId": "session_123",
  "occurredAt": "2026-07-06T00:00:00.000Z",
  "data": {
    "sessionId": "session_123",
    "occurredAt": "2026-07-06T00:00:00.000Z",
    "session": {
      "id": "session_123",
      "label": "Discovery call",
      "memo": null,
      "status": "recording",
      "startedAt": "2026-07-06T00:00:00.000Z",
      "endedAt": null,
      "createdAt": "2026-07-06T00:00:00.000Z",
      "updatedAt": "2026-07-06T00:00:00.000Z"
    }
  }
}

Was this page helpful?