Skip to main content

Lifecycle Webhooks

Lifecycle webhooks publish agent runtime events to an HTTPS endpoint configured on the agent. They are different from channel provider webhooks under /webhooks/{accountId}/{agentId}/{channel}.

Check out the webhook example for setup and usage. Lifecycle webhooks remain declarative HTTPS delivery; they do not upload or execute user hook code.

Code-First Configuration

Configure lifecycle webhooks inside defineAgent. An agent can register several webhooks — hooks.webhooks is an array, so events can fan out to multiple services:

broods/index.ts
import { defineAgent, env } from "broods";

export const myAgent = defineAgent({
name: "my-agent",
config: {
provider: { openai: { apiKey: env.OPENAI_API_KEY } },
model: { provider: "openai", modelId: "gpt-5.5" },
hooks: {
webhooks: [
{
enabled: true,
url: "https://example.com/agent-events",
secret: env.WEBHOOK_SECRET,
events: [
"agent.started",
"tool.call.started",
"tool.call.finished",
"tool.result",
"subagent.task.finished",
"agent.finished",
"agent.failed",
],
},
{
enabled: true,
url: "https://audit.example.com/agent-events",
secret: env.AUDIT_WEBHOOK_SECRET,
events: ["agent.failed"],
},
],
},
},
});
FieldTypeDescription
enabledbooleanEnables delivery for this webhook
urlstringHTTPS endpoint that receives event JSON
secretstringHMAC signing secret
eventsstring[]Optional allow-list; omitted means all lifecycle events

Each entry is delivered independently: every enabled webhook whose events allow-list matches (or is omitted) receives the event. The url must be a public HTTPS endpoint — loopback, private (RFC 1918), link-local, and internal hostnames are rejected at config time and again at delivery, and delivery does not follow redirects.

Whether you configure webhooks in code (config.hooks.webhooks, with url/secret as env.NAME references) or in the dashboard, they are surfaced in the dashboard Settings → Webhooks tab. There you can add a webhook, toggle each one active/inactive, or remove it; the panel writes straight to config.hooks.webhooks (the config the harness delivers from) rather than a separate store. The CLI shows them via broods agent get <name>.

Events

EventEmitted when
agent.startedA model loop starts
agent.step.finishedA Vercel AI SDK step finishes
agent.finishedThe agent produces a final response
agent.failedThe model loop or post-generation handling fails
agent.approval.requiredA tool approval request pauses the turn
tool.call.startedA tool call starts
tool.call.finishedA tool call finishes or fails
tool.resultTool results are available from a finished step
subagent.task.startedA subagent task is dispatched
subagent.task.finishedA subagent task completes or fails

Delivery

Each event is sent as JSON:

{
"type": "tool.call.finished",
"timestamp": "2026-05-17T20:00:00.000Z",
"accountId": "acct_...",
"agentId": "agent_...",
"eventId": "acct:...:api:...",
"conversationKey": "acct:...:conversation:...",
"payload": {
"success": true
}
}

The request is signed with:

X-Webhook-Signature: sha256=<hmac-sha256(secret, raw-json-body)>

Delivery is best-effort. Failures are logged and do not fail the agent turn.