Documentation Index
Fetch the complete documentation index at: https://docs.cerca.dev/llms.txt
Use this file to discover all available pages before exploring further.
This page lists every webhook event Cerca emits, with the payload shape and a representative JSON example. For the delivery model, signing, and retry semantics, see Webhooks. For the receive path, see Receiving webhooks.
Envelope
Every delivery shares the same outer shape. The event-specific payload lives under data; everything else identifies which agent, fleet, and thread the event belongs to.
| Field | Type | Description |
|---|
id | string | Stable ID for this event. Mirrors the X-Agent-Delivery-Id header and is the right key to dedupe on. |
event | string | The event type, e.g. thread.completed. Mirrors X-Agent-Event. |
timestamp | string | ISO 8601 timestamp the event was generated at. |
agentId | string | Agent the event belongs to. |
orgId | string | Organization that owns the agent. |
fleetId | string | Fleet the subscription is scoped to. |
threadId | string | null | Thread the event belongs to, if any. null for agent- and connection-level events. |
data | object | Event-specific payload. See sections below. |
{
"id": "evt_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"event": "thread.completed",
"timestamp": "2026-05-04T12:00:00.000Z",
"agentId": "agent_abc123",
"orgId": "org_acme",
"fleetId": "fleet_internal_ops",
"threadId": "thread_xyz789",
"data": {
"status": "idle",
"previousStatus": "running",
"result": "Booked the flight and emailed the itinerary."
}
}
Agent
agent.created
Fired when a new agent is provisioned in the fleet.
| Field | Type | Description |
|---|
agent | Agent | The full agent record, minus internal-only fields. |
{
"agent": {
"id": "agent_abc123",
"userId": "user_carol",
"orgId": "org_acme",
"fleetId": "fleet_internal_ops",
"configuration": {
"model": "claude-sonnet-4-5",
"instructions": "You are a research assistant.",
"tools": []
},
"metadata": { "team": "research" },
"createdAt": "2026-05-04T12:00:00.000Z",
"updatedAt": "2026-05-04T12:00:00.000Z"
}
}
agent.updated
Fired when an agent’s configuration or metadata changes. trigger distinguishes the two so you can decide whether to invalidate cached config.
| Field | Type | Description |
|---|
trigger | "configuration" | "metadata" | Which kind of change triggered the event. |
agent | Agent | The agent record after the update. |
{
"trigger": "configuration",
"agent": {
"id": "agent_abc123",
"userId": "user_carol",
"orgId": "org_acme",
"fleetId": "fleet_internal_ops",
"configuration": {
"model": "claude-sonnet-4-5",
"instructions": "You are a research assistant. Cite your sources.",
"tools": []
},
"metadata": { "team": "research" },
"createdAt": "2026-05-04T12:00:00.000Z",
"updatedAt": "2026-05-04T12:05:00.000Z"
}
}
agent.deleted
Fired when an agent is deleted. The agent record is no longer retrievable, so only the ID is included.
| Field | Type | Description |
|---|
agentId | string | The deleted agent’s ID. |
{
"agentId": "agent_abc123"
}
Thread
Thread status values are "idle", "running", "awaiting", or "closed".
thread.created
Fired when a new thread starts on an agent. The threadId is on the envelope.
| Field | Type | Description |
|---|
message | string | The user message that opened the thread. |
model | string | Model the thread was created against. |
{
"message": "Plan a three-day trip to Lisbon.",
"model": "claude-sonnet-4-5"
}
thread.status.changed
Fired on every thread status transition. Use this when you want to track every state change; use thread.completed and thread.failed if you only care about runs that finished.
| Field | Type | Description |
|---|
status | ThreadStatus | The new status. |
previousStatus | ThreadStatus | The status before the transition. |
result | string | null | Final result if the thread is closing successfully. |
error | string | null | Error message if the thread is failing. |
{
"status": "awaiting",
"previousStatus": "running",
"result": null,
"error": null
}
thread.completed
Fired when a running or awaiting thread settles back to idle with a result. A thread can complete multiple times over its lifetime — once per run that finishes successfully. Always paired with a thread.status.changed event for the same transition.
| Field | Type | Description |
|---|
status | ThreadStatus | Currently always "idle" at runtime, but the contract is typed as the full ThreadStatus union — don’t write a typed handler that asserts the literal "idle". |
previousStatus | ThreadStatus | The status before the transition ("running" or "awaiting"). |
result | string | The run’s final result. |
{
"status": "idle",
"previousStatus": "running",
"result": "Booked the flight and emailed the itinerary."
}
thread.failed
Fired when a running or awaiting thread settles back to idle with an error. Like thread.completed, this can fire more than once over a thread’s lifetime.
| Field | Type | Description |
|---|
status | ThreadStatus | Currently always "idle" at runtime, but the contract is typed as the full ThreadStatus union — don’t write a typed handler that asserts the literal "idle". |
previousStatus | ThreadStatus | The status before the transition ("running" or "awaiting"). |
error | string | The error message. |
{
"status": "idle",
"previousStatus": "running",
"error": "Tool call exceeded retry budget: search_flights"
}
Turn
A turn is one user-message-and-response exchange inside a thread.
turn.created
Fired when a new turn starts. seq orders turns within a thread.
| Field | Type | Description |
|---|
turnId | string | The new turn’s ID. |
seq | number | Monotonic sequence number within the thread. |
message | string | The user message that opened this turn. |
startedAt | string | ISO 8601 timestamp the turn started. |
{
"turnId": "turn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"seq": 3,
"message": "Now book the cheapest of the three.",
"startedAt": "2026-05-04T12:00:00.000Z"
}
turn.completed
Fired when a turn finishes successfully.
| Field | Type | Description |
|---|
turnId | string | The turn’s ID. |
seq | number | Sequence number within the thread. |
status | "completed" | Always "completed" for this event. |
result | string | null | The turn’s result text, if any. |
error | string | null | Always null for completed turns; included for shape parity with turn.failed. |
tokenUsage | TokenUsage | null | Input and output token counts, when available. |
completedAt | string | ISO 8601 timestamp the turn finished. |
{
"turnId": "turn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"seq": 3,
"status": "completed",
"result": "Booked TAP flight TP202 for $312.",
"error": null,
"tokenUsage": {
"inputTokens": 1842,
"outputTokens": 256
},
"completedAt": "2026-05-04T12:00:08.000Z"
}
turn.failed
Fired when a turn ends in failure. Same shape as turn.completed with a "failed" status and a populated error.
| Field | Type | Description |
|---|
turnId | string | The turn’s ID. |
seq | number | Sequence number within the thread. |
status | "failed" | Always "failed" for this event. |
result | string | null | Partial result, if any. |
error | string | null | Error message describing the failure. |
tokenUsage | TokenUsage | null | Token usage up to the point of failure. |
completedAt | string | ISO 8601 timestamp the turn ended. |
{
"turnId": "turn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"seq": 3,
"status": "failed",
"result": null,
"error": "Tool call exceeded retry budget: book_flight",
"tokenUsage": {
"inputTokens": 1842,
"outputTokens": 64
},
"completedAt": "2026-05-04T12:00:08.000Z"
}
Message
message.created
Fired when a new user or assistant message is appended to a thread. Tool messages and intermediate assistant content do not fire this event — use thread streaming for the full transcript.
The message body is not included in this payload. You only get the role and metadata; to read what was actually said, fetch the message via the API or subscribe to thread streaming.
| Field | Type | Description |
|---|
turnId | string | null | Turn the message belongs to, if any. |
seq | number | Monotonic sequence number within the thread. |
role | "user" | "assistant" | Who authored the message. |
createdAt | string | ISO 8601 timestamp the message was created. |
{
"turnId": "turn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"seq": 7,
"role": "assistant",
"createdAt": "2026-05-04T12:00:08.000Z"
}
Approval
approval.requested
Fired when a tool call requires human approval before running. Surface the approval to a human and resolve it via the API; the resolution drives an approval.resolved event.
| Field | Type | Description |
|---|
approval | PublicWebhookApprovalRequest | The approval request, including tool, input, and timeout. |
{
"approval": {
"id": "approval_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"threadId": "thread_xyz789",
"turnId": "turn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"toolName": "book_flight",
"runtimeToolName": "book_flight",
"input": {
"carrier": "TAP",
"flightNumber": "TP202",
"priceUsd": 312
},
"toolUseId": "toolu_01ABC",
"toolIndex": 0,
"status": "pending",
"timeoutMs": 3600000,
"timeoutAt": "2026-05-04T13:00:00.000Z",
"createdAt": "2026-05-04T12:00:00.000Z",
"resolvedAt": null
}
}
approval.resolved
Fired when an approval reaches a terminal state — approved by a human, denied, timed out, or cancelled because the thread moved on.
| Field | Type | Description |
|---|
approvalId | string | ID of the resolved approval. |
decision | "approved" | "denied" | "timed_out" | "cancelled" | How the approval was resolved. |
{
"approvalId": "approval_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"decision": "approved"
}
approval.granted
Fired when a user grants standing approval for a tool, scoped to either a single thread or the whole agent. Subsequent calls to that tool within the scope skip the approval step.
| Field | Type | Description |
|---|
scope | "thread" | "agent" | Scope the grant applies to. |
toolName | string | Tool the grant covers. |
threadId? | string | Thread the grant applies to, when scope is "thread". |
grantId | string | ID of the new grant. |
{
"scope": "thread",
"toolName": "book_flight",
"threadId": "thread_xyz789",
"grantId": "grant_01HZX9F4G2N3K7B0Q1WVYE6T8M"
}
Schedule
schedule.created
Fired when an agent creates a schedule via the agent.schedule.* namespace.
| Field | Type | Description |
|---|
scheduleId | string | The new schedule’s ID. |
name | string | Human-readable name. |
cron? | string | Cron expression, when the schedule is recurring. |
runAt? | string | ISO 8601 timestamp, when the schedule is one-shot. |
{
"scheduleId": "sched_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"name": "Weekly research digest",
"cron": "0 9 * * MON"
}
schedule.deleted
Fired when a schedule is removed.
| Field | Type | Description |
|---|
scheduleId | string | The removed schedule’s ID. |
{
"scheduleId": "sched_01HZX9F4G2N3K7B0Q1WVYE6T8M"
}
schedule.triggered
Fired when a schedule fires and starts a thread. The new thread’s ID is in the payload; the envelope’s threadId also points at it.
| Field | Type | Description |
|---|
scheduleId | string | Schedule that fired. |
threadId | string | Thread the schedule started. |
{
"scheduleId": "sched_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"threadId": "thread_xyz789"
}
Connection
connection.attached
Fired when a connection is attached to an agent. Pair this with connection.detached to keep your own view of which integrations the agent currently has.
| Field | Type | Description |
|---|
connectionId | string | Connection that was attached. |
provider | string | Provider identifier, e.g. "google" or "slack". |
{
"connectionId": "conn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"provider": "google"
}
connection.detached
Fired when a connection is removed from an agent.
| Field | Type | Description |
|---|
connectionId | string | Connection that was detached. |
provider | string | Provider identifier. |
{
"connectionId": "conn_01HZX9F4G2N3K7B0Q1WVYE6T8M",
"provider": "google"
}
Test
webhook.test
Synthetic event fired only by POST /fleets/{fleetId}/webhooks/{id}/test. The payload data is always {}. This event is not subscribable — you cannot include "webhook.test" in a subscription’s events array on create or update — and it does not appear in ALL_WEBHOOK_EVENT_TYPES. Treat it as a probe for verifying the receive path; ignore unknown event types in your handler so a future test event does not fail closed.