Change feed and webhooks

Keep an external system in sync with a brain.

Two ways to find out what changed: poll the change feed, or subscribe to webhooks. Most integrations use webhooks for latency and the feed for reconciliation.

The change feed

Every meaningful mutation emits an event with an action:

created · updated · renamed · merged · split · archived · restored · recovered · routed

1for await (const ev of await client.workspace.changes({ brainId, since: lastSyncedAt })) {
2 console.log(ev.action, ev.pageId, ev.fromVersion, "", ev.toVersion);
3}

Filter by pageId to watch one page, or unackedOnly to build an inbox.

Acknowledging

1await client.workspace.ackChange({ brainId, changeId });
2const { acked } = await client.workspace.ackAll({ brainId });

Acknowledgement is a user-facing read marker, not a delivery receipt. For machine sync, track since yourself — acking is for “the human has seen this.”

Webhooks

Register an endpoint and receive events as they happen.

1const { secret, ...sub } = await client.webhooks.create({
2 url: "https://api.example.com/hooks/livingbrain",
3 events: ["brain.page.updated", "brain.change.new", "brain.connection.new"],
4});
5// Store `secret` now — it is never returned again.

The signing secret is returned only on creation. If you lose it, delete the subscription and register a new one.

Events

EventFires when
brain.page.updatedA page’s content or metadata changed
brain.change.newA new change event was recorded
brain.connection.newA new connection was discovered
brain.brief.readyA daily brief finished generating
brain.import.progressA long-running import advanced

Managing subscriptions

1const subs = await client.webhooks.list();
2await client.webhooks.update({ id, events: ["brain.brief.ready"] });
3await client.webhooks.remove({ id });

Listing never includes secrets. Updating a subscription leaves its secret unchanged.

Daily briefs

A brain can generate a scheduled digest. Configure the schedule, or trigger one on demand:

1await client.brains.updateBriefSettings({
2 brainId,
3 briefSettings: { enabled: true, hourLocal: 8, timezone: "America/New_York" },
4});
5const brief = await client.brains.runBrief({ brainId });

Subscribe to brain.brief.ready rather than polling — generation is not instant.