Skip to content
simailDocsv0

Integrate

Realtime (WebSocket)

Stream simail events over a WebSocket from a server-side agent; subscribing, limits, revocation and reconnecting without gaps.

docs.simail.ai/realtime

Long-running agents can keep one connection open and receive events as they happen.

GETwss://api.simail.ai/v0/ws

Needs event_read. Authenticate the upgrade request with Authorization: Bearer <key>. This is for server-side agents only: never put an API key in a browser.

import WebSocket from "ws";
const ws = new WebSocket("wss://api.simail.ai/v0/ws", {
headers: { Authorization: `Bearer ${process.env.SIMAIL_API_KEY}` },
});
ws.on("open", () => {
ws.send(JSON.stringify({ type: "subscribe", inbox_ids: ["shop-helper@simail.email"], event_types: ["message.received", "thread.locked"] }));
});
ws.on("message", (raw) => {
const msg = JSON.parse(raw.toString());
if (msg.type === "event") handle(msg.event); // de-duplicate on msg.event.event_id
});
ws.on("close", (code) => scheduleReconnect(code));

Client to server, optional, any time:

{ "type": "subscribe", "inbox_ids": ["shop-helper@simail.email"], "event_types": ["message.received"], "include_non_wake": false }

A subscription can only narrow what your key may see. Without one you get every event in your key’s scope that woke your agent.

Server to client:

{ "type": "event", "event": { "event_id": "evt_…", "event_type": "message.received", "occurred_at": "2026-10-18T17:02:12Z", "inbox_id": "shop-helper@simail.email", "thread_id": "thr_…", "message_id": "msg_…", "data": { "wake": true } } }

The event object is the same thin payload as everywhere else; see Event types. Events that did not wake your agent are skipped unless you subscribe with include_non_wake: true.

  • A connection lives at most 1 hour (less if the key expires sooner). Then it closes and you reconnect, which re-checks the key.
  • Revoking or narrowing the key, removing the member, signing out a console session or pausing the organization closes affected connections at once with code 4401 (revoked).
  • 50 connections per organization, 10 per key, 10 handshakes per minute.
  • A client that falls more than 1 MiB behind is disconnected.
  • Pings are answered by the server without waking anything; idle connections are cheap.

The WebSocket is a fast path, not a log. To never miss an event, remember the event_id of the last event you handled and, after reconnecting, catch up with GET /v0/events using your stored cursor. De-duplicate on event_id. Back off between reconnects (for example 1 s, 2 s, 4 s … up to 60 s) and do not reconnect after 4401 with the same key: it was revoked or narrowed.