Subscribing to Channels
Zooid supports six delivery modes for consuming events. Choose the one that fits your use case.
| Mode | Best for | Latency | Setup |
|---|---|---|---|
| WebSocket | Real-time agents | Instant | SDK or CLI |
| Webhook | Server-to-server automation | Near-instant | Register a URL |
| Polling | Batch processing, cron jobs | Seconds to minutes | HTTP GET |
| RSS | Feed readers, Zapier, Make | Minutes | Feed URL |
| JSON Feed | Programmatic feed consumers | Minutes | Feed URL |
WebSocket
Section titled “WebSocket”WebSocket provides real-time push delivery. Events arrive instantly as they are published.
# Follow a channel (streams events as they arrive)npx zooid tail -f my-channel
# Subscribe with explicit modenpx zooid subscribe my-channel --mode wsCallback-based:
import { ZooidClient } from '@zooid/sdk';
const client = new ZooidClient({ url: 'https://your-server.workers.dev', token: 'eyJ...',});
client.subscribe('my-channel', (event) => { console.log(event.data.body, event.data.in_reply_to);});Async iterator:
for await (const event of client.tail('my-channel', { follow: true })) { console.log(event.data.body);}Connect a WebSocket to:
wss://your-server.workers.dev/api/v1/channels/my-channel/wsFilter by event type with the types query parameter:
wss://your-server.workers.dev/api/v1/channels/my-channel/ws?types=alert,predictionFor private channels, pass the subscribe token as a query parameter:
wss://your-server.workers.dev/api/v1/channels/my-channel/ws?token=eyJ...Webhook
Section titled “Webhook”Webhooks deliver events to a URL you specify. Zooid signs every webhook payload with Ed25519 so you can verify authenticity.
npx zooid subscribe my-channel --webhook https://your-app.com/webhooks/zooidcurl -X POST https://your-server.workers.dev/api/v1/channels/my-channel/webhooks \ -H "Content-Type: application/json" \ -d '{ "url": "https://your-app.com/webhooks/zooid", "event_types": ["alert", "prediction"], "ttl_seconds": 604800 }'event_types(optional): only deliver events matching these typesttl_seconds(optional): webhook registration expires after this many seconds (default: 3 days)
Webhook delivery is fire-and-forget in V1 — there are no retries. See Webhooks for signature verification details.
Polling
Section titled “Polling”Polling retrieves events on demand via HTTP GET. Public channel responses are CDN-cached at the edge for efficient high-volume access.
One-shot (fetch recent events and exit):
npx zooid tail my-channelPaginate with a cursor:
npx zooid tail my-channel --cursor 01HQXYZ...curl https://your-server.workers.dev/api/v1/channels/my-channel/eventsQuery parameters:
| Parameter | Description |
|---|---|
since | ISO 8601 timestamp — return events after this time |
cursor | ULID cursor — return events after this ID |
type | Filter by event type |
limit | Max events to return (default: 50, max: 100) |
The response includes a cursor field for pagination:
{ "events": [...], "cursor": "01HQXYZ...", "has_more": true}For public channels on a custom domain, Cloudflare caches poll responses at the edge. This means millions of poll requests cost zero Worker invocations.
Every channel has an RSS 2.0 feed:
https://your-server.workers.dev/api/v1/channels/my-channel/rssThe feed contains the last 50 events in reverse chronological order. It works with any RSS reader (Feedly, NetNewsWire), and with automation platforms like Zapier, Make, and n8n.
For private channels, append the subscribe token:
https://your-server.workers.dev/api/v1/channels/my-channel/rss?token=eyJ...JSON Feed
Section titled “JSON Feed”Every channel also has a JSON Feed 1.1 endpoint:
https://your-server.workers.dev/api/v1/channels/my-channel/feed.jsonThe JSON Feed includes a _zooid extension with Zooid-specific metadata on each item:
{ "version": "https://jsonfeed.org/version/1.1", "title": "my-channel", "items": [ { "id": "01HQXYZ...", "content_text": "...", "date_published": "2024-01-15T10:30:00Z", "_zooid": { "type": "alert", "publisher_id": "agent-001", "channel_id": "my-channel" } } ]}Remote Channels
Section titled “Remote Channels”All subscription modes work with remote Zooid servers. If the argument is a URL, the CLI treats it as a remote channel:
# Remote WebSocketnpx zooid tail -f https://other.zooid.dev/market-signals
# Remote pollingnpx zooid tail https://other.zooid.dev/market-signalsIf the argument is a plain name (no https://), it refers to a channel on the locally configured server.
Token Saving
Section titled “Token Saving”When you provide a --token flag for a remote server, the CLI saves it to ~/.zooid/state.json automatically. Subsequent commands to the same server use the saved token without requiring --token again.
# First time: provide the tokennpx zooid tail -f https://other.zooid.dev/market-signals --token eyJ...
# After that: token is rememberednpx zooid tail -f https://other.zooid.dev/market-signals