Search docs ⌘K
esc
Type to search across all documentation pages
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

POST
/infra/channels/{channel}/publish
channels:publish0.00000045 tokens per message

Publish a single event.

curl
curl -X POST https://api.saasignal.saastemly.com/infra/channels/{channel}/publish \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"event":"metric.updated","data":{"key":"value"}}'
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 }
})
  1. Open Dashboard and select your project
  2. Go to Channels in the sidebar
  3. Enter a channel name, event name, and JSON payload
  4. Click Publish
The dashboard also shows a live subscriber count and message log.
Path param
Type
Description
channel required
string
Channel name (1–128 chars). Alphanumeric, hyphens, underscores, dots, colons, @.
1–128 charspattern ^[\w.:@-]+$
Body field
Type
Description
event required
string
Event name (e.g. metric.updated)
data required
any JSON
Event payload
id
string
Custom event ID for deduplication
user_id
string
Sender user ID (included in presence)
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Batch Publish

POST
/infra/channels/publish
channels:publish0.00000045 tokens per message

Publish events to one or more channels (max 50 messages per request).

curl
curl -X POST https://api.saasignal.saastemly.com/infra/channels/publish \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"messages":[]}'
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' } },
])
  1. Batch publish is an API-only feature
  2. Use the REST API or TypeScript SDK for bulk publishing
You can publish to individual channels in DashboardChannels
Body field
Type
Description
messages required
array
Array of messages (max 50). Each: { channel, event, data, id?, user_id? }.
1–50 items
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Subscribe to Channel

GET
/infra/channels/{channel}/subscribe
channels:subscribe

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()
  1. Open Dashboard and select your project
  2. Go to Channels and select a channel
  3. 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 required
string
Channel name (1–128 chars)
1–128 charspattern ^[\w.:@-]+$
Query param
Type
Description
last_event_id
string
Resume from this event ID. Replays missed messages (max 128 chars).
max 128 charspattern ^[\w-]+$
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Get Presence

GET
/infra/channels/{channel}/presence
channels:subscribe0.0000008 tokens per request

Get currently connected clients.

curl
curl https://api.saasignal.saastemly.com/infra/channels/{channel}/presence \
  -H "Authorization: Bearer sk_live_..."
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
  1. Open Dashboard and select your project
  2. Go to Channels and select a channel
  3. The Presence tab shows who's currently connected
Path param
Type
Description
channel required
string
Channel name (1–128 chars)
1–128 charspattern ^[\w.:@-]+$
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited

Message History

GET
/infra/channels/{channel}/history
channels:subscribe0.0000008 tokens per request

Retrieve message history for a channel. Use the before parameter for backward pagination.

curl
curl https://api.saasignal.saastemly.com/infra/channels/{channel}/history \
  -H "Authorization: Bearer sk_live_..."
json — 200 OK
{ "status": "ok" }
typescript
const history = await ss.infra.channels.history('org:acme', { limit: 20 })
// history.messages
  1. Open Dashboard and select your project
  2. Go to Channels and select a channel
  3. The History tab shows recent messages
Path param
Type
Description
channel required
string
Channel name (1–128 chars)
1–128 charspattern ^[\w.:@-]+$
Query param
Type
Description
limit
integer
Max messages to return. Range 1–1000, default 50.
range ≥1 .. ≤1000default 50
before
string
Return messages before this event ID (for pagination).
max 128 charspattern ^[\w-]+$
Error responses
401 Unauthorized
402 Insufficient tokens
429 Rate limited