Skip to content
BrainRoad BrainRoad
Documentation Menu

Event Streaming (SSE)

Subscribe to real-time agent events via Server-Sent Events. Get notified when your agent receives messages, executes tools, or encounters errors.

On this page

Real-Time Events

The SSE endpoint streams events from your agent in real time. Use it to:

  • Monitor your agent’s activity from external dashboards
  • Trigger workflows when specific events occur
  • Log agent actions to external systems
  • Build custom notifications

Connecting

curl -N https://app.brainroad.com/api/v1/events \
  -H "Authorization: Bearer brk_your_key_here"

The -N flag disables buffering so events appear immediately.

Authentication

SSE uses API keys (not gateway tokens). Create one from Dashboard → API → API Keys.

Event Format

event: connected
data: {"agentId":"abc123","message":"Subscribed to events"}

event: activity
data: {"id":42,"agentId":"abc123","eventType":"message.received","category":"communication","status":"completed","title":"New WhatsApp message from John","detail":{"from":"+1234567890"},"costTokens":null,"costUsd":null,"source":"webhook","createdAt":"2026-03-09T12:00:00.000Z","resolvedAt":null,"resolvedBy":null}

The first event is always connected with your agent ID. Subsequent events are activity with the full event payload.

Event Fields

FieldTypeDescription
idnumberUnique event ID
agentIdstringYour agent’s ID
eventTypestringSpecific event type (e.g., message.received, tool.executed, agent.started)
categorystringEvent category (see below)
statusstringcompleted, pending_approval, approved, rejected, failed
titlestringHuman-readable event summary
detailobject/nullEvent-specific data (parsed from JSON)
costTokensnumber/nullToken usage, if applicable
costUsdnumber/nullCost in USD (converted from micro-dollars)
sourcestringWhere the event originated: api, webhook, or log
createdAtstringISO 8601 timestamp
resolvedAtstring/nullWhen a pending event was resolved
resolvedBystring/nullWho resolved a pending event

Filtering by Category

Add a category query parameter to receive only specific event types:

# Only communication events (messages received/sent)
curl -N "https://app.brainroad.com/api/v1/events?category=communication" \
  -H "Authorization: Bearer brk_your_key_here"

# Only errors
curl -N "https://app.brainroad.com/api/v1/events?category=error" \
  -H "Authorization: Bearer brk_your_key_here"

Available categories: lifecycle, communication, tool_use, coding, social, config, error

Keepalive

The server sends a comment (: keepalive) every 30 seconds to prevent connection timeouts. Your SSE client library handles these automatically.

Example: Node.js

import EventSource from "eventsource";

const es = new EventSource(
  "https://app.brainroad.com/api/v1/events",
  { headers: { Authorization: "Bearer brk_your_key_here" } }
);

es.addEventListener("activity", (event) => {
  const data = JSON.parse(event.data);
  console.log(`[${data.category}] ${data.title}`);

  if (data.costUsd) {
    console.log(`  Cost: $${data.costUsd.toFixed(4)}`);
  }
});

es.addEventListener("connected", (event) => {
  console.log("Subscribed:", JSON.parse(event.data));
});

es.onerror = () => {
  console.log("Connection lost, reconnecting...");
};

Example: Python

import json
import sseclient  # pip install sseclient-py
import requests

response = requests.get(
    "https://app.brainroad.com/api/v1/events",
    headers={"Authorization": "Bearer brk_your_key_here"},
    stream=True,
)

client = sseclient.SSEClient(response)
for event in client.events():
    if event.event == "connected":
        print("Connected:", json.loads(event.data))
    elif event.event == "activity":
        data = json.loads(event.data)
        print(f"[{data['category']}] {data['title']}")

Example: Browser (fetch)

const response = await fetch("https://app.brainroad.com/api/v1/events", {
  headers: { Authorization: "Bearer brk_your_key_here" },
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const text = decoder.decode(value);
  for (const line of text.split("\n")) {
    if (line.startsWith("data: ")) {
      const data = JSON.parse(line.slice(6));
      console.log(data);
    }
  }
}