Real-time events
How to connect to the Socket.IO server, which channel to join, and how notifications are shaped.
The WebSocket server is a separate Socket.IO deployment. If a server you run needs to react to changes without holding a connection open, use webhooks instead. Connect with a Socket.IO client (the SDK's socket namespace, or socket.io-client directly), never with a raw WebSocket.
Channels
A channel is a Socket.IO namespace named after the resource you want to watch:
| Address | Delivers |
|---|---|
/user/{userId} | Everything addressed to one user: mentions, member chats, task assignments. You may only join your own. |
/workspace/{workspaceId} | Workspace-level changes. |
/project/{projectId} | Project-level changes for the default audience. |
/project/{projectId}/{visibility} | Changes scoped to creator, reviewer or public. Join both creator and reviewer if your role spans both. |
/chat/{chatId} | One chat's stream, plus the collab relay (cursors, drawing, presenter control). |
/asset/{assetId}, /task/{taskId}, /submission/{submissionId} | One resource's stream. |
/public/{token} | A public release, authenticated by the token in the address. |
Joining requires the matching canGet…Notifications permission, direct or inherited; a refused handshake surfaces as connect_error with the message forbidden.
Handshake
Pass your credential as token in the handshake query: a personal access token against ws.nurama.com, or a bot API key against bot-ws.nurama.com. Public channels need no token.
import { io } from 'socket.io-client';
const socket = io(`https://ws.nurama.com/project/${projectId}/creator`, {
query: { token: process.env.NURAMA_TOKEN },
});
socket.on('notification', (event) => console.log(event.type, event));When a credential is revoked the server emits tokenEvent and disconnects shortly after.
The notification envelope
Almost everything arrives as a single event named notification. Its type field names one of the notification types; tokens carries the identifiers the type documents, and changes lists created, updated and deleted resources:
{
"type": "chatCreateMessage",
"initiatorId": "…",
"tokens": { "chatId": "…", "messageId": "…" },
"changes": { "create": [{ "resourceType": "chatMessage", "resource": { "…": "…" } }] }
}Switch on type and read the documented payload. Fields marked deprecated in a type's schema will disappear; prefer the changes array over legacy token fields.
Other events
Typing indicators (typing:start, typing:stop) are emitted by clients and relayed by the server, ws:probe checks liveness, and the collab:* family relays live-collaboration state on /chat/{chatId} namespaces. Each is documented under Events with its direction and payload.
The complete machine-readable description is the AsyncAPI document at /asyncapi.json.