> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhook payloads

> Event webhook bodies and generated SDK schemas

Configure an [event webhook](/agents/configuration#event-webhook) to receive JSON POST requests with `event` and `data`. The event name determines the data schema. These are the same data objects used by the [event stream](/events/streaming).

Webhook deliveries are suppressed for deleted projects and organizations, including events produced by their deletion.

Every request includes `Webhook-Id` (stable across retries) and `Webhook-Timestamp` (Unix seconds for that attempt). Signed requests also include `Webhook-Signature`. Verify the signature against the raw request body before parsing it, using [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md).

## Receive and verify

The SDK includes the TypeScript type `EventWebhookPayload` and the Zod schema `zEventWebhookPayload` for validating incoming webhook payloads.

Install `@omnara/sdk` and `standardwebhooks`. Set `WEBHOOK_SIGNING_SECRET` to the same base64 value stored in the agent config's signing secret. This Node.js server verifies the raw body before validating the payload; missing, invalid, or expired signatures are rejected.

```typescript theme={null}
import { createServer } from 'node:http'
import { buffer } from 'node:stream/consumers'
import { zEventWebhookPayload } from '@omnara/sdk/zod'
import { Webhook } from 'standardwebhooks'

const secret = process.env.WEBHOOK_SIGNING_SECRET
if (!secret) throw new Error('set WEBHOOK_SIGNING_SECRET')
const verifier = new Webhook(secret)

createServer(async (request, response) => {
  if (request.method !== 'POST' || request.url !== '/webhook') {
    response.writeHead(404).end()
    return
  }
  try {
    const rawBody = await buffer(request)
    let payload
    try {
      const verified = verifier.verify(rawBody, {
        'webhook-id': String(request.headers['webhook-id'] ?? ''),
        'webhook-timestamp': String(request.headers['webhook-timestamp'] ?? ''),
        'webhook-signature': String(request.headers['webhook-signature'] ?? ''),
      })
      payload = zEventWebhookPayload.parse(verified)
    } catch {
      response.writeHead(400).end('invalid webhook')
      return
    }
    console.log('received', payload.event)
    response.writeHead(204).end()
  } catch {
    response.writeHead(500).end()
  }
}).listen(3000)
```

Expose `/webhook` over public HTTPS. This snippet only validates and acknowledges events. For custom-tool execution and duplicate handling, see the runnable [custom-tool webhook example](https://github.com/omnara-ai/omnara/tree/main/examples/custom-tool-webhook).

## Payload examples

Timeline events include event, agent, project, organization, and turn identifiers, an event sequence, and a creation timestamp. The examples below include all required fields; the OpenAPI schemas describe optional fields and content-block variants.

> **Agent input (`agent_input`)**
>
> ```json theme={null}
> {
>   "event": "agent_input",
>   "data": {
>     "id": "evt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "org_id": "org_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "project_id": "proj_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "agent_id": "agt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_id": "trn_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_sequence": 1,
>     "is_opening_event": true,
>     "sequence": 1,
>     "event_kind": "agent_input",
>     "agent_input_id": "ain_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "input_kind": "content",
>     "content_blocks": [
>       {
>         "type": "text",
>         "text": "Summarize the report."
>       }
>     ],
>     "created_at": "2026-09-18T12:00:00Z"
>   }
> }
> ```

> **Model output (`model_output`)**
>
> ```json theme={null}
> {
>   "event": "model_output",
>   "data": {
>     "id": "evt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "org_id": "org_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "project_id": "proj_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "agent_id": "agt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_id": "trn_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_sequence": 1,
>     "is_opening_event": false,
>     "sequence": 3,
>     "event_kind": "model_output",
>     "model_call_context_id": "mcc_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "stop_reason": "end_turn",
>     "content_blocks": [
>       {
>         "type": "text",
>         "text": "The report shows steady growth."
>       }
>     ],
>     "created_at": "2026-09-18T12:00:00Z"
>   }
> }
> ```

> **Tool result (`tool_result`)**
>
> ```json theme={null}
> {
>   "event": "tool_result",
>   "data": {
>     "id": "evt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "org_id": "org_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "project_id": "proj_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "agent_id": "agt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_id": "trn_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_sequence": 1,
>     "is_opening_event": false,
>     "sequence": 3,
>     "event_kind": "tool_result",
>     "tool_call_id": "tcl_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "outcome": "succeeded",
>     "content_blocks": [
>       {
>         "type": "text",
>         "text": "Ticket created."
>       }
>     ],
>     "created_at": "2026-09-18T12:00:00Z"
>   }
> }
> ```

> **Context checkpoint (`context_checkpoint`)**
>
> ```json theme={null}
> {
>   "event": "context_checkpoint",
>   "data": {
>     "id": "evt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "org_id": "org_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "project_id": "proj_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "agent_id": "agt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_id": "trn_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "turn_sequence": 1,
>     "is_opening_event": false,
>     "sequence": 3,
>     "event_kind": "context_checkpoint",
>     "context_checkpoint_id": "ccp_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "summarized_through_event_sequence": 2,
>     "summary": "The user requested a report summary.",
>     "created_at": "2026-09-18T12:00:00Z"
>   }
> }
> ```

> **Tool-call update (`tool_call_update`)**
>
> ```json theme={null}
> {
>   "event": "tool_call_update",
>   "data": {
>     "tool_call_id": "tcl_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "agent_id": "agt_5n6a2bfgik7mv4qtrwz3jehcyd",
>     "state": "awaiting_permission",
>     "interaction_update": {
>       "id": "int_5n6a2bfgik7mv4qtrwz3jehcyd",
>       "interaction_kind": "permission",
>       "state": "open"
>     }
>   }
> }
> ```

`tool_call_update` is a notification to fetch the tool call or interaction for its current details. It carries a state snapshot, not the tool arguments or a timeline sequence. For custom execution, handle `ready` updates and deduplicate by tool-call ID. Self-subagents send their own agent IDs; profile subagents use their own webhook configuration.

When a permission or question opens or closes, `interaction_update` includes its ID, kind, and state (`open`, `resolved`, or `canceled`). Omission means no interaction change. Track interactions by ID; a terminal update takes precedence over a late `open` update. Fetch interactions when you need the full form.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.