Getting Started
Go from zero to a live chat session: mint a user token on your backend, install the client SDK, connect over WebSocket, and send your first message.
1. Server token
Authenticate with Basic Auth and mint a user token via POST /v1/chat-sdk/users/token.
2. Install SDK
Add @sendexa/chat-sdk to your web or React Native app. One package for both runtimes.
3. Connect
Call init with the user token, then connect() to open the managed WebSocket session.
4. Send & listen
Use sendMessage and on('message') to exchange messages in real time.
npm
@sendexa/chat-sdk
<5 min
with a test channel
2
Web + React Native
WSS
TLS WebSocket
Authentication
Authorization: Basic <token>. Auth guide →Prerequisites
- A Sendexa account with Chat SDK enabled (Beta). Copy the Base64 dashboard token from the dashboard for server calls.
- A backend that can authenticate your app users (session, JWT, OAuth, etc.). Chat tokens must only be issued after that check succeeds.
- Node.js 18+ (or a modern browser / React Native 0.72+) for the client package.
Step 1 — Mint a user token
Your server calls Sendexa with the dashboard Basic Auth credential and receives a short-lived user token. That token is the only credential the client ever sees.
| Field | Type | Required | Description |
|---|---|---|---|
| userId | string | required | Stable id for this user in your system (max 128 chars). Used for membership and message authorship. |
| displayName | string | optional | Human-readable name shown in chat UIs (max 80 chars). Can be updated on later mints. |
| ttl | number | optional | Token lifetime in seconds. Default 3600. Allowed range: 300–86400 (5 minutes–24 hours). |
curl -X POST 'https://api.sendexa.co/v1/chat-sdk/users/token' \-H 'Content-Type: application/json' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-d '{"userId": "user_01HZX9K2M","displayName": "Ama Mensah","ttl": 3600}'
{"success": true,"code": "CHAT_USER_TOKEN_ISSUED","message": "User chat token minted.","requestId": "REQ-1782001100001","timestamp": "2026-07-12T10:00:00.000Z","data": {"userId": "user_01HZX9K2M","displayName": "Ama Mensah","token": "chat_usr_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJ1c2VyXzAxSFpYOUsyTSIsImV4cCI6MTc4Mzg1NDgwMH0.signature","expiresAt": "2026-07-12T11:00:00.000Z","ttl": 3600}}
Step 2 — Install the client SDK
npm install @sendexa/chat-sdk
Never ship the dashboard API key
Step 3 — Init, connect, and listen
Fetch the user token from your API, initialise the SDK, open the socket, and subscribe to events before sending.
import { SendexaChat } from '@sendexa/chat-sdk';async function startChat() {// 1) Get a short-lived token from YOUR backendconst { token, expiresAt } = await fetch('/api/chat/token', {method: 'POST',credentials: 'include',}).then((r) => r.json());// 2) Initialise the SDKconst chat = SendexaChat.init({token,// Optional overrides (defaults shown):// apiUrl: 'https://api.sendexa.co',// wsUrl: 'wss://chat.sendexa.co/v1/ws',// autoReconnect: true,// logLevel: 'warn',});// 3) Register handlers BEFORE connect so you never miss eventschat.on('connected', () => {console.log('Chat connected');});chat.on('disconnected', ({ reason }) => {console.warn('Chat disconnected', reason);});chat.on('message', (message) => {// message: { id, channelId, userId, body, createdAt, metadata? }console.log(`[${message.channelId}] ${message.userId}: ${message.body}`);});chat.on('error', (err) => {console.error('Chat error', err.code, err.message);});// 4) Open the WebSocketawait chat.connect();// 5) Schedule a refresh before expiry (example: 60s early)const msUntilRefresh =new Date(expiresAt).getTime() - Date.now() - 60_000;if (msUntilRefresh > 0) {setTimeout(async () => {const next = await fetch('/api/chat/token', {method: 'POST',credentials: 'include',}).then((r) => r.json());await chat.updateToken(next.token);}, msUntilRefresh);}return chat;}const chat = await startChat();
Step 4 — Create a channel and send
Channels are usually created by your server so membership stays authoritative. Then any member can send messages from the client or REST.
curl -X POST 'https://api.sendexa.co/v1/chat-sdk/channels' \-H 'Content-Type: application/json' \-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \-d '{"type": "dm","name": "Support · Ama","memberIds": ["user_01HZX9K2M", "agent_support_01"],"metadata": {"ticketId": "TCK-1042"}}'
{"id": "msg_01HZYB8P","channelId": "ch_01HZYA3N","userId": "user_01HZX9K2M","body": "Hi — I need help with my order.","type": "text","metadata": {"clientMessageId": "local-uuid-1"},"createdAt": "2026-07-12T10:05:12.441Z","seq": 1}
Presence, typing & read receipts
Once connected, the same client instance exposes lightweight real-time helpers. Full detail lives on the Channels & Messages page.
// Presencechat.on('presence', ({ userId, status, lastSeenAt }) => {// status: 'online' | 'away' | 'offline'console.log(userId, status, lastSeenAt);});// Typingawait chat.startTyping('ch_01HZYA3N');// stops automatically after ~3s, or call stopTypingchat.on('typing', ({ channelId, userId, isTyping }) => {console.log(channelId, userId, isTyping);});// Read receiptsawait chat.markRead({channelId: 'ch_01HZYA3N',messageId: 'msg_01HZYB8P', // or omit to mark latest});chat.on('read', ({ channelId, userId, messageId, readAt }) => {console.log('Read by', userId, messageId, readAt);});
- Enable Chat SDK on your Sendexa business and copy the Basic Auth token
- Implement
POST /api/chat/token(or equivalent) that calls/v1/chat-sdk/users/token - Install
@sendexa/chat-sdkand wireinit+connect - Create at least one channel with known member ids for testing
- Send a message from the client and confirm
on('message')on a second device/session - Configure webhooks for server-side events
Users & Auth
Token TTL, refresh, revoke, and identity rules.
Channels & Messages
REST history, send paths, presence and receipts.
Webhooks
chat.message.created and membership events.
Best Practices
- Register event listeners before
connect()to avoid race conditions - Use a local optimistic UI keyed by
metadata.clientMessageId, then reconcile with the serverid - Call
disconnect()on logout and when React trees unmount - Refresh tokens proactively — do not wait for a 401 mid-conversation