Real-time (SSE)
RSMG Engage streams live discussion activity over Server-Sent Events (SSE). To subscribe, mint a
short-lived, single-use ticket from your backend, then open an EventSource to the stream with
that ticket.
1. Mint a ticket (backend)
POST /api/v1/stream/ticket-by-external
X-API-Key: ek_…
Content-Type: application/json
{ "externalId": "article-123" }
{ "data": { "ticket": "…", "discussionId": "…", "expiresAt": "…", "discussionStatus": "open" } }
Tickets are short-lived (~60 s) and single-use, so mint one per connection. You can also mint by
UUID via POST /api/v1/stream/ticket with { "discussionId": "…" }.
2. Connect (client)
const es = new EventSource(
`https://{slug}.rsmg-engage.com/api/v1/stream/${discussionId}?ticket=${ticket}`,
);
es.addEventListener('comment_created', (e) => render(JSON.parse(e.data)));
The ticket is the only credential the browser needs — no API key reaches the client.
Reconnection is free: EventSource auto-reconnects (the server sends retry: 5000) and missed
events are replayed via Last-Event-ID — no client work needed.
Event types
| Event | When |
|---|---|
comment_created | A comment is posted |
comment_edited | A comment body changes |
comment_deleted | A comment is removed (carries deletedBy) |
comment_approved / comment_rejected | Moderation decision on a pending comment |
comment_pinned / comment_unpinned | Admin pins/unpins |
reaction_toggled | A reaction is added/removed |
discussion_locked / discussion_unlocked / discussion_archived | Discussion lifecycle change |
notification_reply | Someone replied to a reader's comment — delivered to every subscriber on the discussion, so filter on recipientUserId before notifying |
Two framing events bracket the stream: connected on subscribe, and connection-timeout when a
long-lived connection is cycled.
New event types may be added over time — ignore event names you don't recognise.
Suppressing your own echoes
Comment and reaction events include originatedBy: { userId: string | null } — the acting reader's
internal user id, which is null for admin actions. If your client knows the internal id, match
on it to skip echoing an action you just performed locally. (Discussion lifecycle events carry
actor/at/reason instead, and notification_reply carries neither.)
For clients that don't hold internal ids, reaction_toggled also carries a sibling
externalUserId field — the reacting reader's external (your-side) id. Match it against your
local viewer to self-suppress without ever seeing internal ids.
See Stream in the API Reference for payload shapes, and Webhooks for server-to-server delivery of the same events.