Channels
Channels
Real-time pub/sub backed by Cloudflare Durable Objects. Each channel is a persistent WebSocket hub — publish from your API route, subscribe from the browser via WebSocket or SSE. Channels maintain presence state and message history automatically.
Architecture: Each unique
channel name maps to a dedicated Durable Object. The DO holds connections, fans out messages, tracks presence, and keeps a sliding history window. There's no separate "create channel" step — channels are created on first access.Publish Event
GET
json — 202 Accepted
{ "channel": "org:acme", "event_id": "evt_01JNXS...", "delivered": 3 }
typescript
await ss.infra.channels.publish('org:acme', {
event: 'metric.updated',
data: { mrr: 42840, delta: +1200 }
})
- Open Dashboard and select your project
- Go to Channels in the sidebar
- Enter a channel name, event name, and JSON payload
- Click Publish
The dashboard also shows a live subscriber count and message log.
Path param
Type
Description
channel requiredstring
Channel name (1–128 chars). Alphanumeric, hyphens, underscores, dots, colons,
@.Body field
Type
Description
event requiredstring
Event name (e.g.
metric.updated)data requiredany JSON
Event payload
idstring
Custom event ID for deduplication
user_idstring
Sender user ID (included in presence)
Error responses
400 Invalid body (validation error)
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
Batch Publish
GET
json — 202 Accepted
[
{ "channel": "org:acme", "event_id": "evt_01JNXS...", "delivered": 3 },
{ "channel": "org:beta", "event_id": "evt_01JNXT...", "delivered": 1 }
]
typescript
await ss.infra.channels.batchPublish([
{ channel: 'org:acme', event: 'metric.updated', data: { mrr: 42840 } },
{ channel: 'org:beta', event: 'alert', data: { level: 'warn' } },
])
- Batch publish is an API-only feature
- Use the REST API or TypeScript SDK for bulk publishing
You can publish to individual channels in Dashboard → Channels
Body field
Type
Description
messages requiredarray
Array of messages (max 50). Each:
{ channel, event, data, id?, user_id? }.Error responses
400 Invalid body (validation error)
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
Subscribe to Channel
GET
Subscribe to a channel. Send Upgrade: websocket to get a WebSocket connection; otherwise you get an SSE stream (text/event-stream).
javascript
const ws = new WebSocket(
'wss://api.saasignal.saastemly.com/infra/channels/org:acme/subscribe',
['Bearer', 'sk_live_...']
)
ws.onmessage = (e) => {
const { id, event, data } = JSON.parse(e.data)
console.log(event, data)
}
javascript
// SSE — proxy through your own API route for auth
const es = new EventSource('/api/subscribe?channel=org:acme')
es.addEventListener('metric.updated', (e) => {
const data = JSON.parse(e.data)
setMRR(data.mrr)
})
typescript
// Browser SDK handles auth via your /api/saasignal proxy
const channel = ss.infra.channels.subscribe('org:acme')
channel.on('metric.updated', (data) => setMRR(data.mrr))
channel.on('user.joined', (data) => addUser(data))
// Cleanup
return () => channel.close()
- Open Dashboard and select your project
- Go to Channels and select a channel
- The channel monitor shows live messages as they arrive
You can also view presence (who's connected) and full message history.
Resume on reconnect: Store the last event ID from
e.lastEventId and pass it as ?last_event_id= on reconnect. SaaSignal replays missed messages from the channel history.Path param
Type
Description
channel requiredstring
Channel name (1–128 chars)
Query param
Type
Description
last_event_idstring
Resume from this event ID. Replays missed messages (max 128 chars).
Error responses
401 Unauthorized
402 Insufficient Tokens
429 Rate Limited
Get Presence
GET
json — 200 OK
{
"channel": "org:acme",
"count": 3,
"users": [
{ "user_id": "u_123", "joined_at": "2026-03-04T12:00:00Z" },
{ "user_id": "u_456", "joined_at": "2026-03-04T12:01:30Z" }
]
}
typescript
const presence = await ss.infra.channels.presence('org:acme')
// presence.count, presence.users
- Open Dashboard and select your project
- Go to Channels and select a channel
- The Presence tab shows who's currently connected
Path param
Type
Description
channel requiredstring
Channel name (1–128 chars)
Error responses
401 Unauthorized
402 Insufficient Tokens
404 Channel not found
429 Rate Limited
Message History
GET
typescript
const history = await ss.infra.channels.history('org:acme', { limit: 20 })
// history.messages
- Open Dashboard and select your project
- Go to Channels and select a channel
- The History tab shows recent messages
Path param
Type
Description
channel requiredstring
Channel name (1–128 chars)
Query param
Type
Description
limitinteger
Max messages to return. Range 1–1000, default
50.beforestring
Return messages before this event ID (for pagination).
Error responses
401 Unauthorized
402 Insufficient Tokens
404 Channel not found
429 Rate Limited