WebSocket

Receive real-time SMS delivery status updates and inbound SMS notifications over a persistent WebSocket connection.

WS/wsIn-band (first message after connect)

Upgrade to a WebSocket connection for real-time events.

Connection URL

text
wss://smsgateway-api.onrender.com/ws

Authentication

After opening the WebSocket connection, the first message must be an auth message. No other messages are processed until authentication succeeds. Two authentication methods are supported:

Token-based authentication (recommended for browsers)

Use ephemeral tokens when the WebSocket connection originates from a browser or any environment where you do not want to expose the API key. Request a token server-side, then pass it to the client for authentication.

POST/v1/ws/tokenapp

Generate a short-lived, single-use token for WebSocket authentication.

Response

NameTypeRequiredDescription
tokenstringRequiredEphemeral token prefixed with wst_. Single-use; consumed when used to authenticate a WebSocket connection.
expiresInintegerRequiredToken lifetime in seconds (currently 60). The token cannot be used after this period.
200 OK
json
{
"token": "wst_a1b2c3d4e5f6789012345678abcdef90a1b2c3d4e5f6789012345678abcdef90",
"expiresIn": 60
}
Request token
curl -X POST https://smsgateway-api.onrender.com/v1/ws/token \
-H "Authorization: Bearer YOUR_API_KEY"

Then authenticate the WebSocket connection with the token:

Send (token auth)
{
"type": "auth",
"token": "wst_a1b2c3d4e5f6789012345678abcdef90a1b2c3d4e5f6789012345678abcdef90"
}
Token lifecycle
Tokens are single-use and expire after 60 seconds. Once the WebSocket connection is authenticated, the token is consumed and the connection persists independently — there is no need to refresh the token while the connection remains open. Request a new token only when reconnecting.

API key authentication (server-to-server)

For server-side applications, you can authenticate directly with your API key. Only use this method in environments where the key is not exposed to end users.

Send (API key auth)
{
"type": "auth",
"apiKey": "sgw_a1b2c3d4e5f6789012345678abcdef90"
}

Success

Receive
{
"type": "auth_ok"
}

Errors

On auth failure, the server sends an error message and closes the connection with code 1008 (Policy Violation).

Invalid JSON
{
"type": "auth_error",
"error": "Invalid JSON"
}
Invalid API key
{
"type": "auth_error",
"error": "Invalid API key"
}
Invalid or expired token
{
"type": "auth_error",
"error": "Invalid or expired token"
}
Message before auth
{
"type": "auth_error",
"error": "Send auth first"
}

Event types

sms_status

Sent when an outbound message changes status (queued → sending → sent/failed).

sms_status — sent
{
"type": "sms_status",
"messageId": "msg_a1b2c3d4e5f6",
"appId": "app_abc123def456abcd",
"tenantId": "tenant_abc123def456abcd",
"status": "sent",
"rcMessageId": "12345678",
"timestamp": "2026-03-01T10:00:02.000Z"
}
sms_status — failed
{
"type": "sms_status",
"messageId": "msg_a1b2c3d4e5f6",
"appId": "app_abc123def456abcd",
"tenantId": "tenant_abc123def456abcd",
"status": "failed",
"error": "Phone number +15559876543 is not registered in this RingCentral account",
"timestamp": "2026-03-01T10:00:02.000Z"
}

sms_inbound

Sent when an inbound SMS is received.

sms_inbound
{
"type": "sms_inbound",
"messageId": "msg_f6e5d4c3b2a1",
"from": "+15551234567",
"to": "+15559876543",
"body": "Hey, is my appointment still on?",
"rcMessageId": "12345678",
"tenantId": "tenant_abc123def456abcd",
"timestamp": "2026-03-01T14:30:00.000Z"
}

ping

Heartbeat sent by the server every 30 seconds. No response required.

ping
{
"type": "ping"
}

Event scoping

Events are scoped to your account. You will only receive events for your own apps and tenant.

Event scoping works identically for both authentication methods. A token inherits the same role and tenant scope as the API key that generated it.

Example — token auth (browser)

javascript
// 1. Request an ephemeral token from your server
const res = await fetch("/api/ws-token");
const { token, wsUrl } = await res.json();
// 2. Connect to the gateway WebSocket
const ws = new WebSocket(wsUrl + "/ws");
ws.onopen = () => {
// 3. Authenticate with the token (API key stays server-side)
ws.send(JSON.stringify({ type: "auth", token }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case "auth_ok":
console.log("Authenticated");
break;
case "sms_status":
console.log("Status update:", data.messageId, data.status);
break;
case "sms_inbound":
console.log("Inbound SMS:", data.from, data.body);
break;
case "ping":
break;
}
};

Example — API key auth (server)

javascript
const ws = new WebSocket("wss://smsgateway-api.onrender.com/ws");
ws.onopen = () => {
ws.send(JSON.stringify({
type: "auth",
apiKey: "YOUR_API_KEY"
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case "auth_ok":
console.log("Authenticated");
break;
case "sms_status":
console.log("Status update:", data.messageId, data.status);
break;
case "sms_inbound":
console.log("Inbound SMS:", data.from, data.body);
break;
case "ping":
break;
}
};

Related docs