Start with an explicit stream set
The documented endpoint is wss://ws.api.synoptic.com/v1/on-stream-post. A reader key controls access; streamIds narrows which accessible streams are delivered. If you omit that filter, the connection can include every stream the key can read.
Generate a reader key in Synoptic settings and keep it server-side. The example below passes the key in a header to avoid putting it into the URL. This integration sample requires an account, eligible stream access and the websocket-client package; it was not run with credentials.
import json, os
from urllib.parse import urlencode
import websocket # pip install websocket-client
query = urlencode({"streamIds": os.environ["SYNOPTIC_STREAM_ID"], "lastPosts": 50})
url = "wss://ws.api.synoptic.com/v1/on-stream-post?" + query
ws = websocket.create_connection(
url, header=["x-api-key: " + os.environ["SYNOPTIC_READER_KEY"]], timeout=30
)
try:
while True:
frame = json.loads(ws.recv())
if frame.get("event") == "stream.post.created":
# Persist frame first; queue post-processing after the write succeeds.
print(json.dumps(frame))
else:
# Log frame type; handle catch-up, info and errors separately.
print("control/event:", frame.get("event"))
finally:
ws.close()Account-dependent illustration, not a production client. It prints rather than persists, and has no retry loop. Add durable storage, bounded queues and recovery before operating it.
Plan for a gap larger than the catch-up window
The subscription guide caps lastPosts at 50 recent posts in total across the connected streams. That is a bounded convenience, not a durable cursor promising complete replay. It also sends a different event type, stream.post.last-posts, which the small live-event sample does not process.
Persist the latest saved timestamps and IDs. After an interruption, query accessible stored history with REST date bounds and pagination, overlap the window and deduplicate. History availability and stream entitlements still need verification. A larger outage may require a separate backfill plan.
Make overload and disconnects visible
- Use reconnect delay with jitter; the official overview warns against tight loops.
- Keep receipt time, source time and queue age separately so a stalled worker is observable.
- If a bounded queue fills, raise an explicit degraded-state alert rather than silently dropping records.
- Store raw frames before model work and make duplicate handling idempotent.
- Test disconnects and incomplete catch-up in your own environment; no delivery guarantee is established by this example.
Source notes
- Synoptic WebSocket subscriptions ↗
Live event envelope, streamIds and limited lastPosts catch-up.
- Synoptic WebSocket overview ↗
Reader keys, control messages and reconnection guidance.
- Synoptic REST reference ↗
Stored posts, source metadata, date bounds and retrieval constraints.
The Synoptic workflow
Build with Synoptic
Choose source streams and confirm account access before connecting your agent.
Build with Synoptic