WebSocket Events
Connect to the WebSocket endpoint for real-time delivery of SMS status updates and inbound messages. WebSocket is an alternative to polling the status endpoint and complements webhook delivery.
When to use this
- Track outbound message status changes in real time (
queued→sending→sent/failed). - Receive inbound SMS instantly without waiting for webhook delivery.
- Build dashboards or monitoring interfaces with live message feeds.
When not to use this
- Server-to-server integrations where webhooks are more reliable (no persistent connection needed).
- Low-frequency polling is sufficient for your use case.
Connecting
Open a WebSocket connection to the /ws endpoint:
const ws = new WebSocket("wss://smsgateway-api.onrender.com/ws");
Authentication
Authentication happens in-band. After the connection opens, send your API key as the first message:
ws.onopen = () => {ws.send(JSON.stringify({ type: "auth", apiKey: "YOUR_API_KEY" }));};
The server responds with a confirmation:
{"type": "auth_ok"}
If the API key is invalid:
{"type": "auth_error","error": "Invalid API key"}
Event types
sms_status
Published when an outbound message changes status:
{"type": "sms_status","messageId": "msg_a1b2c3d4e5f6","appId": "app_abc123def456abcd","tenantId": "tenant_abc123def456abcd","status": "sent","rcMessageId": "123456789","timestamp": "2026-03-01T10:00:01.000Z"}
{"type": "sms_status","messageId": "msg_a1b2c3d4e5f6","appId": "app_abc123def456abcd","tenantId": "tenant_abc123def456abcd","status": "failed","error": "RingCentral not connected for this tenant","timestamp": "2026-03-01T10:00:02.000Z"}
sms_inbound
Published when an inbound SMS is received:
{"type": "sms_inbound","messageId": "msg_c3d4e5f6a1b2","from": "+15559876543","to": "+15551234567","body": "Yes, I confirm","rcMessageId": "123456789","tenantId": "tenant_abc123def456abcd","timestamp": "2026-03-01T14:30:00.000Z"}
ping
The server sends a heartbeat every 30 seconds to keep the connection alive:
{"type": "ping"}
Event scoping
Events are filtered based on the authenticated connection's role:
approle — Receives events for messages matching the app'sappIdandtenantId.adminrole — Receives all events across all tenants and apps.
Reconnection
WebSocket connections can be dropped by network issues, server restarts, or idle timeouts. Implement automatic reconnection with exponential backoff:
let retryDelay = 1000;const MAX_DELAY = 30000;function connect() {const ws = new WebSocket("wss://smsgateway-api.onrender.com/ws");ws.onopen = () => {retryDelay = 1000;ws.send(JSON.stringify({ type: "auth", apiKey: "YOUR_API_KEY" }));};ws.onmessage = (event) => {const data = JSON.parse(event.data);if (data.type === "ping") return;if (data.type === "auth_ok") return;// Handle sms_status, sms_inbound eventsconsole.log("Event:", data);};ws.onclose = () => {setTimeout(() => {retryDelay = Math.min(retryDelay * 2, MAX_DELAY);connect();}, retryDelay);};}connect();
Missed events
Events sent while the connection is down are not queued or replayed. To recover missed events after reconnecting:
- Query
GET /v1/sms/messageswith astartDatefilter to fetch messages created since the connection dropped. - Check individual message status with
GET /v1/sms/status/:messageIdfor any in-flight messages.
webhookUrl on your app in addition to using WebSocket. Webhooks and WebSocket events are delivered independently.Best practices
- Authenticate immediately — Send the auth message as soon as the connection opens to start receiving events.
- Handle ping events — Acknowledge or ignore ping events gracefully. Do not treat them as errors.
- Implement reconnection — Always reconnect with exponential backoff when the connection closes.
- Parse defensively — Validate the
typefield before processing. Ignore unknown event types to maintain forward compatibility.
Related docs
- WebSocket API Reference — Endpoint details
- Sending SMS — Outbound message lifecycle
- Receiving SMS — Inbound message flow
- Webhooks — Alternative delivery mechanism