Realtime WebSocket messaging
Real-time messaging API for the Freeday webchat, powered by Centrifugo. The typed message payloads are in the Message schemas reference; this page covers how the protocol works.
Quick Start
| Service | URL |
|---|---|
| REST API | https://api.freeday.ai |
| WebSocket | wss://realtime.freeday.ai |
All REST calls require X-Session-Id (client-generated UUID) and X-Company (from Settings → Company in the Freeday platform) headers.
Pass X-Channel-Id as well to keep each channel's conversation history separate: when it is set, listing conversations and reading their messages is limited to the digital employees routed from that channel, so a conversation started in one widget or app does not surface in another.
- Create a conversation —
POST /sdk/v1/conversations - Get a connection token —
POST /sdk/v1/auth/connect-token - Connect — Open a WebSocket to
wss://realtime.freeday.ai/connection/websocketwith the token. See the Centrifugo client SDK docs. - Get a subscription token —
POST /sdk/v1/auth/subscribe-token - Subscribe — Subscribe to the
channelfrom step 4 with agetTokencallback.
Example (centrifuge-js):
const sub = client.newSubscription(channel, {
getToken: async () => {
const res = await fetch("https://api.freeday.ai/sdk/v1/auth/subscribe-token", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Session-Id": sessionId, "X-Company": companyId },
body: JSON.stringify({ conversation_id: conversationId }),
});
return (await res.json()).subscription_token;
},
});
sub.on("publication", (ctx) => handleEnvelope(ctx.data));
sub.subscribe();
Authentication
JWT tokens are used for both connection and channel subscription authentication:
- Connection token — obtained via
POST /sdk/v1/auth/connect-token(15 min expiry). See the REST API reference. - Subscription token — obtained via
POST /sdk/v1/auth/subscribe-token(24 hour expiry). See the REST API reference.
Conversation channel
Channel address: messages:companies.{companyId}.conversations.{conversationId}
companyId— UUID of the companyconversationId— UUID of the conversation
Clients subscribe to receive messages from the digital employee, agents, and system, and publish to send user messages.
History: 100 messages are retained for 1 hour. See the Centrifugo history documentation for retrieval details.
Message flow
Sending: Publish a SendMessage via subscription.publish().
Receiving: The server streams MessageEnvelope objects. Each envelope carries a sequence number — discard out-of-order envelopes, and ignore envelopes with an unrecognized proto version. A message streams in via replace → … → complete.
Streaming example:
{ "operation": "replace", "sequence": 1, "message_snapshot": { "status": "partial", "blocks": [{ "id": "b1", "type": "typing", "typing": true }] } }
{ "operation": "replace", "sequence": 2, "message_snapshot": { "status": "partial", "blocks": [{ "id": "b2", "type": "markdown", "content": "Hello! I can" }] } }
{ "operation": "complete", "sequence": 3, "message_snapshot": { "status": "complete", "blocks": [{ "id": "b2", "type": "markdown", "content": "Hello! I can help you with that." }] } }
Message schemas
The full typed payloads (MessageEnvelope, Message, SendMessage, block types, …) are in the Message schemas reference nested under this section. The machine-readable AsyncAPI 3.1 spec is available in the repo at docs/async-api/webchat-sdk-async.yaml.