Channels and connections
How a realtime connection is opened, kept alive and re-opened; publishing and receiving; channel names; message size, rate and ordering; catching up with replay; closing codes; encrypted channels; and limits.
The connection
Ticket
The client asks for a one-time ticket for a channel (
POST /api/v1/auth/ws-ticket). Your rules decide here whether the caller may subscribe; a ticket works once and expires within seconds.Connect
The client opens
wss://<project-ref>.sovarias.in/api/v1/rt/ws/<channel>?ticket=….Stay alive
The connection is kept alive with a heartbeat every 30 seconds; a connection silent for 90 seconds is treated as gone.
Re-open
If it drops, the SDK reconnects with backoff (at most 15 seconds between tries, configurable) and a fresh ticket each time.
const room = sovaria.realtime.channel('room-42', {
onMessage: (payload) => addMessage(payload),
onStatus: (status) => setStatus(status), // 'connecting' | 'live' | 'reconnecting' | 'closed'
onError: (err) => console.warn(err), // it keeps retrying
maxBackoffMs: 15000,
})
await room.send({ text: 'Hello!', at: Date.now() })
room.close()Publish and receive
room.send(payload)orsovaria.realtime.publish(channel, payload)sends through the API (POST /api/v1/rt/stream/publish/<channel>); your rules must allowPUBLISHfor the caller.- Servers and functions can publish with the service role key — for example to notify users when a job finishes.
- Every subscriber of the channel, including the sender, receives the message as
{ payload, … }.
Channel names
| Pattern | Use |
|---|---|
room-42, orders | Shared channels; allow them by name in rules. |
user:<user id>, user:<user id>:notifications | A user's private channels; one rule covers them all with ctx.realtime.in_own_channel == True. |
db.table.<table> | Database change events (Database change events). |
Ordering and delivery
- Messages on one channel arrive in the order they were published.
- A message reaches the clients connected at that moment. Each message carries
stream_seq, its number in the channel. A client that was offline catches up with replay:sovaria.realtime.replay(channel, after, limit)returns the messages after the laststream_seqit saw (up to 1,000 per call; the most recent 1,000 per channel are kept). - A client that can't keep up (its socket doesn't accept data within about a second) is disconnected so it doesn't slow the channel down; it reconnects and replays.
let lastSeen = 0
const ch = sovaria.realtime.channel('orders', {
onMessage: (payload, raw) => { lastSeen = raw.stream_seq ?? lastSeen; show(payload) },
onStatus: async (s) => {
if (s === 'live' && lastSeen) {
const missed = await sovaria.realtime.replay('orders', lastSeen, 200)
missed.events?.forEach((e) => show(e.payload))
}
},
})Why a connection closes
| Code | Means | Do |
|---|---|---|
4401 | Not authorized: bad, expired or reused ticket, or the user signed out. | Get a new ticket (the SDK does); if it keeps failing, check the channel rules. |
4408 | Policy violation: a rule or limit refused the connection or a message. | Check rules and limits (message size, events per second). |
1013 | Slow consumer: the client didn't read fast enough. | Reconnect and replay; handle messages faster. |
End-to-end encrypted channels
On paid plans a channel can be end-to-end encrypted: clients fetch the channel's key wrapped for their own public key, encrypt messages before sending and decrypt after receiving, so Sovaria relays them without being able to read them. Keys can be rotated and revoked (REST: realtime and end-to-end encryption).
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| End-to-end encrypted realtime | — | ✓ | ✓ | ✓ | ✓ |
Limits
Per project you can lower these further and cap events per second per connection under Realtime › Settings (Realtime settings and limits).
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Concurrent realtime connections | 100 | 500 | 1,500 | 5,000 | 20,000 |
| Realtime channels | 20 | 500 | 5,000 | 20,000 | 100,000 |
| Realtime connections per signed-in user | 20 | 50 | 100 | 200 | 500 |
| Largest realtime message | 0 MB | 0 MB | 0 MB | 0 MB | 0 MB |
| Monthly realtime messages | 2,000,000 | 5,000,000 | 15,000,000 | 75,000,000 | 300,000,000 |
| Recent realtime messages kept per channel for replay | 1,000 | 1,000 | 1,000 | 1,000 | 1,000 |