Skip to content
Beta. This surface may change before GA; breaking changes are dated in the changelog.

Webhooks

Register a webhook to be notified when runs reach a terminal state — no polling required. The completion payload carries the run’s result inline, so a webhook is often all you need for “fire a run, handle the output later.”

Create a registration with the URL to call and the events you care about (see the API reference for the exact request). You receive a signing secret — store it; you’ll use it to verify deliveries.

Events selectable on an organization-level registration (org-wide, or scoped to one agent or one brain):

Event Fires when
run.created A run starts.
run.completed The run finished successfully.
run.failed The run errored.
run.abandoned The run was cancelled.
task.created / task.completed / task.expired A task changes state.
operation.succeeded / operation.failed / operation.abandoned An operation reaches a terminal state.
knowledge.corrected An accepted brain change was corrected — the one push signal for off-platform consumers of a brain.

Each delivery is a POST with a JSON body:

{
"event": "run.completed",
"timestamp": "2026-06-04T10:00:00.000Z",
"data": {
"runId": "0c7f1e9a-2b4d-4f3a-9c1e-8a2d6f4b0c7f",
"state": "completed",
"status": "succeeded",
"output": { "summary": "Report summarized in three bullet points." }
}
}

The data carries the caller-facing status and the terminal result — output for run.completed, failureReason / failureCategory for run.failed, abandonReason for run.abandoned. You usually don’t need a follow-up GET.

Every delivery includes an X-Nicia-Signature header: sha256=<hex>, an HMAC-SHA256 of the raw request body keyed by your signing secret. Always verify it before trusting a payload.

import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, header: string, secret: string): boolean {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(header);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
}

Failed deliveries are retried with backoff. Make your handler idempotent — the same event may arrive more than once. Respond 2xx to acknowledge.