WebSocket Guide
Real-time WebSocket APIs for notifications, chat, and threat intelligence streaming. Persistent bidirectional connections with automatic reconnection.
Real-Time WebSocket APIs
Persistent bidirectional connections for live notifications, chat messaging, and threat intelligence streaming. Low latency, event-driven, and production-ready.
Overview
OrbVPN provides three WebSocket endpoints across two services. WebSocket connections are persistent, full-duplex channels that allow the server to push events to your client in real time without polling.
Event-Driven Architecture
Subscribe to specific event channels and receive JSON-formatted messages the instant they occur. No polling, no wasted bandwidth.
Automatic Reconnection
SDKs handle reconnection with exponential backoff. Manual implementations should follow the reconnection strategy documented below.
Heartbeat / Keep-Alive
Ping-pong frames keep connections alive through proxies and load balancers. Clients must respond to server pings within 30 seconds.
Connection Flow
Every WebSocket connection follows the same lifecycle, regardless of endpoint.
Endpoints
1. OrbNET Notifications
Real-time notifications for account events, subscription updates, device status changes, and server alerts.
wss://api.orbai.world/ws/notificationsReceive real-time notifications for your OrbVPN account. Requires a valid JWT access token passed as a Bearer token in the initial connection handshake.
notificationsubscription_updatedevice_statusserver_alertNotification Persistence
Notifications are persisted server-side. If your client disconnects, missed notifications are delivered as a batch upon reconnection (up to 100 events, last 24 hours).
2. OrbNET Chat
Real-time messaging for support chat, reseller communication, and in-app messaging.
wss://api.orbai.world/ws/chatBidirectional chat messaging for OrbVPN support and in-app communication. Requires a valid JWT access token.
messagetypingread_receipt3. OrbGuard Threat Stream
Live threat intelligence feed for real-time threat detection and security monitoring.
wss://guard.orbai.world/ws/threatsReal-time threat intelligence stream from OrbGuard Labs. Requires an API key passed via the X-API-Key header or as a query parameter.
threat_detectedscan_completealertThreat Stream Volume
The OrbGuard threat stream can produce high event volumes (100+ events/minute during active campaigns). Implement buffering and rate-limiting in your consumer to avoid overwhelming your application.
Connection Examples
JavaScript
// OrbNET Notifications WebSocket
const token = 'eyJhbGciOiJIUzI1NiIs...';
const ws = new WebSocket(
`wss://api.orbai.world/ws/notifications?token=${token}`
);
ws.onopen = () => {
console.log('Connected to OrbNET notifications');
// Subscribe to specific channels
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['notification', 'device_status', 'subscription_update'],
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'connection_ack':
console.log(`Session: ${data.sessionId}`);
break;
case 'notification':
console.log(`[Notification] ${data.payload.title}: ${data.payload.message}`);
break;
case 'device_status':
console.log(`[Device] ${data.payload.deviceId}: ${data.payload.status}`);
break;
case 'subscription_update':
console.log(`[Subscription] ${data.payload.event}: ${data.payload.planName}`);
break;
case 'server_alert':
console.log(`[Alert] ${data.payload.severity}: ${data.payload.message}`);
break;
default:
console.log('Unknown event:', data);
}
};
ws.onerror = (error) => {
console.error('WebSocket error:', error);
};
ws.onclose = (event) => {
console.log(`Connection closed: ${event.code} ${event.reason}`);
// Implement reconnection logic (see below)
};Python
import asyncio
import json
import websockets
async def connect_notifications():
token = "eyJhbGciOiJIUzI1NiIs..."
uri = f"wss://api.orbai.world/ws/notifications?token={token}"
async for websocket in websockets.connect(uri):
try:
# Subscribe to channels
await websocket.send(json.dumps({
"type": "subscribe",
"channels": ["notification", "device_status"],
}))
async for raw_message in websocket:
event = json.loads(raw_message)
if event["type"] == "connection_ack":
print(f"Connected. Session: {event['sessionId']}")
elif event["type"] == "notification":
payload = event["payload"]
print(f"[Notification] {payload['title']}: {payload['message']}")
elif event["type"] == "device_status":
payload = event["payload"]
print(f"[Device] {payload['deviceId']}: {payload['status']}")
elif event["type"] == "ping":
await websocket.pong()
except websockets.ConnectionClosed:
print("Connection lost. Reconnecting...")
continue # websockets.connect handles reconnection
asyncio.run(connect_notifications())Go
package main
import (
"encoding/json"
"fmt"
"log"
"net/url"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
type Event struct {
Type string `json:"type"`
SessionID string `json:"sessionId,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
}
func main() {
token := "eyJhbGciOiJIUzI1NiIs..."
u := url.URL{
Scheme: "wss",
Host: "api.orbai.world",
Path: "/ws/notifications",
RawQuery: fmt.Sprintf("token=%s", token),
}
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("Connection failed:", err)
}
defer conn.Close()
// Subscribe to channels
subscribe := map[string]interface{}{
"type": "subscribe",
"channels": []string{"notification", "device_status", "server_alert"},
}
conn.WriteJSON(subscribe)
// Handle ping/pong
conn.SetPongHandler(func(appData string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
})
// Graceful shutdown
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
done := make(chan struct{})
go func() {
defer close(done)
for {
var event Event
err := conn.ReadJSON(&event)
if err != nil {
log.Println("Read error:", err)
return
}
switch event.Type {
case "connection_ack":
fmt.Printf("Connected. Session: %s\n", event.SessionID)
case "notification":
fmt.Printf("[Notification] %s\n", string(event.Payload))
case "device_status":
fmt.Printf("[Device] %s\n", string(event.Payload))
case "server_alert":
fmt.Printf("[Alert] %s\n", string(event.Payload))
}
}
}()
select {
case <-done:
case <-interrupt:
log.Println("Shutting down...")
conn.WriteMessage(
websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""),
)
select {
case <-done:
case <-time.After(time.Second):
}
}
}OrbGuard Threat Stream Example
Connecting to the OrbGuard threat intelligence stream uses API key authentication instead of JWT.
// OrbGuard Threat Stream WebSocket
const apiKey = 'ogk_live_abc123...';
const ws = new WebSocket(
`wss://guard.orbai.world/ws/threats?api_key=${apiKey}`
);
ws.onopen = () => {
console.log('Connected to OrbGuard threat stream');
// Subscribe to specific threat categories
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['threat_detected', 'alert'],
filters: {
severity: ['critical', 'high'],
categories: ['malware', 'phishing', 'c2'],
},
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'threat_detected') {
const threat = data.payload;
console.log(`[THREAT] ${threat.severity.toUpperCase()}`);
console.log(` Indicator: ${threat.indicator}`);
console.log(` Type: ${threat.indicatorType}`);
console.log(` Category: ${threat.category}`);
console.log(` Score: ${threat.score}/100`);
}
if (data.type === 'alert') {
const alert = data.payload;
console.log(`[ALERT] ${alert.title}`);
console.log(` ${alert.message}`);
console.log(` Action: ${alert.recommendedAction}`);
}
};Reconnection Strategy
Network interruptions are inevitable. Implement exponential backoff with jitter to reconnect gracefully.
class ReconnectingWebSocket {
constructor(url, options = {}) {
this.url = url;
this.maxRetries = options.maxRetries || 10;
this.baseDelay = options.baseDelay || 1000; // 1 second
this.maxDelay = options.maxDelay || 30000; // 30 seconds
this.retryCount = 0;
this.handlers = {};
this.connect();
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('Connected');
this.retryCount = 0; // Reset on successful connection
this.handlers.open?.();
};
this.ws.onmessage = (event) => {
this.handlers.message?.(JSON.parse(event.data));
};
this.ws.onclose = (event) => {
if (event.code === 1000) return; // Normal closure
if (this.retryCount < this.maxRetries) {
const delay = Math.min(
this.baseDelay * Math.pow(2, this.retryCount) + Math.random() * 1000,
this.maxDelay
);
console.log(`Reconnecting in ${Math.round(delay)}ms (attempt ${this.retryCount + 1})`);
this.retryCount++;
setTimeout(() => this.connect(), delay);
} else {
console.error('Max reconnection attempts reached');
this.handlers.maxRetriesReached?.();
}
};
}
on(event, handler) {
this.handlers[event] = handler;
return this;
}
send(data) {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify(data));
}
}
close() {
this.ws.close(1000, 'Client closing');
}
}
// Usage
const ws = new ReconnectingWebSocket(
`wss://api.orbai.world/ws/notifications?token=${token}`,
{ maxRetries: 10, baseDelay: 1000 }
);
ws.on('open', () => {
ws.send({ type: 'subscribe', channels: ['notification'] });
});
ws.on('message', (data) => {
console.log('Event:', data);
});Heartbeat / Ping-Pong
The server sends WebSocket ping frames every 30 seconds. Clients must respond with a pong frame. If no pong is received within 30 seconds, the server closes the connection.
| Parameter | Value |
|---|---|
| Ping interval | 30 seconds |
| Pong timeout | 30 seconds |
| Max missed pings | 1 (connection closed after 1 missed pong) |
| Client-initiated ping | Supported (server will respond with pong) |
Browser WebSocket
Most browser WebSocket implementations handle ping-pong frames automatically at the protocol level. You only need to handle this explicitly when using low-level WebSocket libraries in server-side languages.
Event Message Format
All WebSocket events follow a consistent JSON format:
{
"type": "notification",
"id": "evt_abc123def456",
"timestamp": "2026-02-08T12:00:00.000Z",
"payload": {
"title": "Subscription Renewed",
"message": "Your OrbVPN Premium plan has been renewed for 12 months.",
"category": "billing",
"priority": "normal",
"metadata": {
"planName": "Premium",
"amount": 99.99,
"currency": "USD"
}
}
}| Field | Type | Description |
|---|---|---|
type | string | Event type (matches the subscribed channel name) |
id | string | Unique event identifier for deduplication |
timestamp | string | ISO 8601 timestamp of when the event was generated |
payload | object | Event-specific data (varies by event type) |
Connection Limits
Connection Limits
WebSocket connections are limited per account and per endpoint:
- Notifications: 5 concurrent connections per user
- Chat: 3 concurrent connections per user
- Threat Stream: 2 concurrent connections per API key
- Total per account: 10 concurrent WebSocket connections
Exceeding these limits returns a 4008 Connection Limit Reached close frame. Existing connections are not affected.
Error Close Codes
WebSocket connections may be closed with the following codes:
| Code | Reason | Action |
|---|---|---|
1000 | Normal closure | No action needed |
1001 | Server going away | Reconnect with backoff |
1008 | Policy violation | Check authentication credentials |
1011 | Internal server error | Reconnect with backoff |
4001 | Authentication failed | Refresh token and reconnect |
4003 | Forbidden | Check permissions for the requested channel |
4008 | Connection limit reached | Close an existing connection before reconnecting |
4029 | Rate limited | Wait for the duration specified in the close reason, then reconnect |
Best Practices
Always Authenticate First
Pass your token in the connection URL or initial message. Never send sensitive data before the connection_ack event.
Subscribe Selectively
Only subscribe to channels you need. Broad subscriptions increase bandwidth and processing overhead.
Deduplicate Events
Use the event ID field for deduplication. On reconnection, you may receive events that were already delivered.
Handle Backpressure
Buffer incoming events and process them asynchronously. Do not block the WebSocket message handler with slow operations.
Go Real-Time
Integrate live notifications, chat, and threat intelligence into your application with OrbVPN's WebSocket APIs. Low latency, high reliability, and simple event-driven architecture.