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

# Webhooks

> Listen to events in your agents so your integration can automatically trigger reactions.

export const ApiProperty = ({name, type, children, required = false}) => {
  return <div className="py-6 border-b border-gray-200 dark:border-gray-700">
      <div className="flex font-mono text-sm group/param-head param-head break-all relative">
        <div className="flex-1 flex content-start py-0.5 mr-5">
          <div className="flex items-center flex-wrap gap-2">
            <div className="font-semibold text-primary dark:text-primary-light cursor-pointer overflow-wrap-anywhere" data-component-part="field-name">
              {name}
            </div>
            <div className="inline items-center gap-2 text-xs font-medium [&_div]:inline [&_div]:mr-2 [&_div]:leading-5" data-component-part="field-meta">
              <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 text-gray-600 dark:text-gray-200 font-medium break-all" data-component-part="field-info-pill">
                <span>{type}</span>
              </div>
              {required && <div className="px-2 py-0.5 rounded-md bg-red-100/50 dark:bg-red-400/10 text-red-600 dark:text-red-300 font-medium whitespace-nowrap" data-component-part="field-required-pill">
                  required
                </div>}
            </div>
          </div>
        </div>
      </div>
      <div className="mt-4">
        <div className="prose prose-sm prose-gray dark:prose-invert">
          <p className="whitespace-pre-line">{children}</p>
        </div>
      </div>
    </div>;
};

When building on Operator, you may want your agents to send real-time events to your application as they run, allowing your backend systems to execute actions accordingly.

To receive webhooks, go to [**Developers → Webhooks**](https://app.operator.xyz/?subpath=%22/developers/webhooks%22) and set your webhook endpoint URL. Once you've set the endpoint, your agents will push real-time event data to your application's webhook endpoint when events happen in your Operator account.

We deliver events through HTTPS POST requests with a JSON payload.

## Verification

All webhook requests are HMAC-signed to ensure request authenticity and prevent replay attacks. You can find your signing key at [**Developers → Webhooks**](https://app.operator.xyz/?subpath=%22/developers/webhooks%22).

Learn more about this scheme in [First-party APIs → Authentication](/docs/tools/first-party).

## Webhook request body

The webhook request body contains a JSON payload representing events emitted by the agent system. Each event includes a unique identifier, timestamp, agent and conversation identifiers, and a payload containing the specific event data. The payload structure varies depending on the event type (setup, ended, custom fields updated, etc.) and contains the relevant information for that particular event.

```json theme={null}
{
  "id": "ev_8qm9JBCiTe7",
  "created_at": "2024-01-15T10:30:00Z",
  "agent_id": "ca_8qm9JBCiTe7@v0",
  "conversation_id": "conv_8qm9JBCiTe7",
  "payload": {
    "type": "conversation.setup",
    "data": {
      // Event-specific data based on the event type
    }
  }
}
```

## Event types

As of today, Operator delivers webhooks for the following event types, for the full schema of these events refer to the [Events schema](/docs/api-reference/conversation-events) page:

### `conversation.setup`

This webhook is sent when a conversation is being set up—for example, when an agent is about to dial a call or has received a call but hasn't yet picked up.

You can return the following configuration and data to this webhook request (similar to the configuration for a [new outbound conversation](/docs/api-reference/conversations/create-a-conversation#body-override-config)):

<ApiProperty name="context" type="object" required>JSON object that will be used as [`context`](/docs/conversational-agents/context) for the conversation. This is the only way to load context into conversations that aren't triggered by an API call, such as incoming phone calls.</ApiProperty>

<ApiProperty name="override_config" type="object">Partial override for [the agent's configuration](/docs/conversational-agents/create-a-conversational-agent#body-config) (e.g. voice, runtime, tools). Follows the same shape as the agent configuration object, but all fields are optional since it is merged into the base config.</ApiProperty>

Read more:

* [Dynamic configuration](/docs/conversational-agents/dynamic-configuration): learn how to customize your agent dynamically at the start of a conversation by replying to the `conversation.setup` webhook with configuration data
* [Conversation context](/docs/conversational-agents/context): learn how context data is used to customize the agent prompt for a conversation

### `conversation.ended`

This webhook is sent when the conversation completes. At this point, you're guaranteed that the conversation has terminated and will have a status of one of the following: `completed`, `failed`, `busy`, `no-answer` or `voicemail`.

### `conversation.custom_fields.updated`

This webhook is sent when a custom field on a conversation is modified. The webhook includes the key that was updated, along with both the new value and the previous value (if any). This allows you to track changes to custom fields and trigger downstream workflows based on field updates.
