bichito
API

Server-Sent Events

Subscribe to a per-team realtime stream of bichito events. Used internally by /inbox; available to external clients.

The dashboard's /inbox uses an SSE stream to update rows live. The stream is a public endpoint — you can subscribe from your own client and react to bichito events without polling.

Endpoint

GET /api/v1/teams/{team_id}/stream?token=<jwt>

The connection is long-lived (the browser holds it open for the lifetime of the tab). Auth happens via the ?token= query param because EventSource in browsers doesn't let you set custom headers.

Auth

Pass your JWT as ?token=<jwt>. Same JWT you'd use for Authorization: Bearer … everywhere else. Sub-resources (which honeycombs, which bichitos) are scoped to the JWT's user; trying to subscribe to a team you don't own returns 404.

Heads up: the JWT in the URL ends up in your server access logs. We log only the path on our side, but if you're proxying through a logging layer, configure it to scrub ?token=.

Events emitted

Four event types today:

EventTriggered byPayload
bug.createdWidget POST /api/v1/bugsFull bichito summary (the inbox row payload).
bug.updatedStatus / severity / assignee / labels / duplicate-of change{ bug_id, project_id, changes: { ... } }
bug.commentedNew comment{ bug_id, project_id, comment_id, author_id }
bug.deletedBichito deleted{ bug_id, project_id }

changes carries only the fields that actually changed. For label changes, it's the full post-change list (so consumers don't need to compute diffs). Example:

event: bug.updated
data: {"bug_id": 42, "project_id": 7, "changes": {"status": "resolved"}}

Heartbeats

Every 30 seconds we send a comment line so proxies / load balancers don't close the connection for being idle:

: heartbeat

These aren't real events — EventSource discards them automatically. If you implement your own SSE client, treat lines starting with : as no-ops.

Reconnection

EventSource reconnects automatically with exponential backoff. We don't issue Last-Event-ID checkpoints today, so you may miss events that happened between disconnect and reconnect. For best-effort triage UIs (the inbox), that's fine. For audit / billing use cases, the dashboard fetch on reconnect catches up the gap.

Per-tab queues, drop policy

Each subscriber gets a 64-event queue server-side. A slow consumer that lets the queue fill (offline tab, network bottleneck) gets the oldest events dropped — we never block the publisher.

In practice this means: if an open tab goes to sleep for an hour, on wake it'll see a recent fragment of the activity, not the whole hour. Refresh to get a clean state.

Scaling

Today the SSE pub/sub is in-process. That works for single-machine deployments (current setup on fly.io). When we add a second worker, we'll switch to a Redis adapter behind the same publish / subscribe API; subscribers don't notice.

Set SSE_BACKEND=redis and REDIS_URL=... to opt into Redis manually.

On this page