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 Dashboard → Channels
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