Skip to main content
Polling GET /transcripts/... works, but for a live UI you want segments pushed as they’re produced. The gateway exposes a multiplexed WebSocket at /ws that fans transcripts out in real time.

Connect and authenticate

Connect to /ws on the gateway and authenticate with your API key — as a header, or as an api_key query parameter when the client can’t set headers:
ws://localhost:18056/ws          # header:  X-API-Key: <API_KEY>
ws://localhost:18056/ws?api_key=<API_KEY>
A missing key gets a missing_api_key error frame; an invalid key is rejected with close code 4401.

Subscribe

Send a subscribe action naming the meetings you want. The socket multiplexes — subscribe to several at once:
{ "action": "subscribe",
  "meetings": [ { "platform": "google_meet", "native_id": "abc-defg-hij" } ] }
The gateway authorizes each meeting against your key and acks with what you’re now subscribed to:
{ "type": "subscribed", "meetings": [ { "platform": "google_meet", "native_id": "abc-defg-hij" } ] }
Transcript segments then stream in as frames. Live drafts arrive as completed: false and are replaced by completed: true confirmations — render the draft, then overwrite it when the confirmation lands. health frames surface engine/no-signal faults in-band.

Unsubscribe and keepalive

{ "action": "unsubscribe", "meetings": [ { "platform": "google_meet", "native_id": "abc-defg-hij" } ] }
{ "action": "ping" }     // → { "type": "pong" }

Example (Node)

import { WebSocket } from "ws";

const ws = new WebSocket("ws://localhost:18056/ws", { headers: { "X-API-Key": process.env.API_KEY } });

ws.on("open", () => ws.send(JSON.stringify({
  action: "subscribe",
  meetings: [{ platform: "google_meet", native_id: "abc-defg-hij" }],
})));

ws.on("message", (raw) => {
  const msg = JSON.parse(raw);
  if (msg.type === "subscribed") return console.log("subscribed", msg.meetings);
  if (msg.segments) for (const s of msg.segments)
    console.log(s.completed ? "✓" : "…", s.speaker, s.text);
});

Error frames

errorMeaning
missing_api_keyno key supplied
invalid_api_keykey rejected (socket closes 4401)
invalid_jsonpayload wasn’t a JSON object
invalid_subscribe_payloadmeetings missing, empty, or has no valid {platform, native_id}
unknown_actionaction wasn’t subscribe / unsubscribe / ping
Prefer pull-based? Stick with polling the transcript endpoint.