Connection
Connection, limits, and response envelope
Endpoint
Connect via secure WebSocket (wss://). Plain ws:// connections are rejected (HTTP 301).
Timestamps
All timestamp fields in stream messages are integers representing milliseconds since the Unix epoch — including notification payloads (time, createdAt, closedAt, …), the time method's result.time, and the authenticate request's timestamp. Encode and decode them as numbers, not ISO-8601 strings.
Response envelope
Every response includes server-side timing metadata:
| Field | Type | Description |
|---|---|---|
usIn | number | Microseconds elapsed when the server received the frame |
usOut | number | Microseconds elapsed when the server sent the response |
usDiff | number | usOut - usIn — server-side handling time |
Responses also include a rateLimit object:
{ "remaining": 9, "limit": 10 }remaining is the number of message tokens still available in the current 1-second window for this connection.
Errors
Errors follow JSON-RPC 2.0:
{
"jsonrpc": "2.0",
"id": 1,
"error": { "code": -32602, "message": "...", "data": { "code": "BAD_REQUEST" } },
"usIn": 0,
"usOut": 0,
"usDiff": 0,
"rateLimit": { "remaining": 9, "limit": 10 }
}error.code is the JSON-RPC error code. Use error.data.code for programmatic handling — it carries the application-level code (e.g. UNAUTHORIZED, BAD_REQUEST, TOO_MANY_REQUESTS, NOT_FOUND, INTERNAL_SERVER_ERROR).
Limits
| Limit | Value |
|---|---|
| Max payload size | 16 KiB |
| Idle timeout | 120 seconds |
| Concurrent connections per IP | 32 |
| New connections per IP per hour | 500 |
| Messages per connection per second | 10 |
| Authenticate attempts per IP per min | 20 |
Connections that exceed the per-IP cap are rejected at the WebSocket layer (the connection is closed by the server). Messages that exceed the per-second budget receive a TOO_MANY_REQUESTS error response with rateLimit.remaining: 0; the budget refills 1 second after the first message in the window.