Skip to content

WebSocket

Hantera exposes a single WebSocket endpoint for real-time communication. This page covers how to open, authenticate and maintain a connection.

Once connected, the protocol offers two capabilities:

  • Event subscription — push notifications when things happen in your system (jobs, actor state changes)
  • Live queries (experimental) — a reactive, server-side query result that updates as data changes

Both are documented in the WebSocket API Reference, which lists every message type.

WARNING

Preview API: The WebSocket API is currently in preview and subject to change before final release.

Endpoint

wss://{hostname}/ws

Replace {hostname} with your tenant hostname (e.g. tenant.core.ams.hantera.cloud).

All messages are JSON text frames. Binary frames are not supported.

Connection Lifecycle

1. Open the connection

typescript
const ws = new WebSocket('wss://{hostname}/ws')

2. Authenticate

The first message must be an auth message containing your access token:

json
{
  "type": "auth",
  "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Send the token without the Bearer prefix. Authentication must complete within 10 seconds, or the server closes the connection with code 4001.

Any other message sent before auth is rejected with AUTH_REQUIRED and closes the connection.

3. Receive confirmation

On success the server replies:

json
{ "type": "authenticated" }

The connection is now ready. You can subscribe to events, create live queries, or both on the same connection.

4. Respond to keep-alive pings

The server sends a ping every 30 seconds. Respond with a pong within 30 seconds or the connection is closed with code 4002:

json
{ "type": "pong" }

Request Correlation

Request messages accept an optional requestId. The server echoes it back on the corresponding response or error, letting you match replies to requests on a connection where many are in flight at once.

json
{
  "type": "...",
  "requestId": "req-1"
}

Because a single connection multiplexes every capability, correlation is the only reliable way to tell which request an error belongs to.

Error Handling

Errors arrive as error messages carrying a machine-readable code:

json
{
  "type": "error",
  "code": "INVALID_PATH",
  "message": "Unknown resource path: invalid/path",
  "requestId": "req-5"
}

Some errors are fatal and close the connection (for example AUTH_FAILED); others are scoped to a single request and leave the connection usable. See the error codes table for the full list and which ones close the connection.

Non-fatal conditions — such as a client consuming messages too slowly — arrive as warning messages instead.

Reconnecting

WebSocket connections drop: networks change, servers redeploy, tokens expire. Treat reconnection as a normal part of the lifecycle.

  1. Reconnect with exponential backoff rather than immediately, to avoid overwhelming the server after an outage.
  2. Re-authenticate — a new connection always starts unauthenticated.
  3. Re-establish subscriptions and live queries. Server-side state is bound to the connection and is discarded when it closes; identifiers from the previous connection are not valid on the new one.
  4. Re-sync your local state from the Graph API. Changes that occurred while you were disconnected are not replayed.

Example

Connecting, authenticating and keeping the connection alive:

typescript
const ws = new WebSocket('wss://core.your-tenant.hantera.cloud/ws')

ws.onopen = () => {
  ws.send(JSON.stringify({ type: 'auth', token: 'your-access-token' }))
}

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data)

  switch (msg.type) {
    case 'authenticated':
      // Connection is ready — subscribe to events or create live queries here.
      break

    case 'ping':
      ws.send(JSON.stringify({ type: 'pong' }))
      break

    case 'warning':
      console.warn(msg.code, msg.message)
      break

    case 'error':
      console.error(msg.code, msg.message)
      break
  }
}

ws.onclose = (event) => {
  // Reconnect with backoff, then re-authenticate and re-establish subscriptions.
  console.log('Disconnected', event.code)
}

Best Practices

  • Reconnect with backoff — re-authenticate and re-establish subscriptions and live queries afterwards.
  • Subscribe selectively — only request the paths, events and queries you actually use, to reduce message volume.
  • Handle overflow warnings — a QUEUE_OVERFLOW warning means data was dropped; re-sync from the Graph API to recover.
  • Release what you don't need — destroy live queries and remove subscriptions when they're no longer in use to free server resources.
  • Use request correlation — include requestId so responses and errors can be matched to their request.

Next Steps

  • WebSocket API Reference — every message type, grouped by capability
  • Graph API — the query language behind live queries
  • Rules — for workflows needing guaranteed delivery, where dropped messages are unacceptable

© 2026 Hantera AB. Org. no.: 559242-9582