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

# Webhooks

> Subscribe to Dome events and deliver signed webhooks to your endpoints or off-the-shelf providers, with retries and replay

export const webhook = "Webhooks deliver selected workspace events as signed HTTP POSTs to your HTTPS endpoint or a provider. A subscription chooses which events to send. A destination receives them.";

<p>
  {webhook}
</p>

Refer to [Webhooks](/concepts/audit/webhooks) concept for how signed delivery works. Refer to [Events](/reference/events#webhooks) reference for the wire contract.

## Overview

A **subscription** matches [Events](/reference/events#webhooks) by type and filter. A **destination** receives them as signed HTTP POSTs. Create both in one call with `subscriptions create`, or attach a second subscription to an existing destination. Providers and custom URLs use the same model. Discover provider fields with `dome webhooks providers list`. Operating limits (body cap, rate, retention) are on [Webhooks](/concepts/audit/webhooks#operating-limits).

The typical workflow is:

1. [Create a subscription](#create-a-subscription) and optional [filters](#filters).
2. [Test](#test-a-subscription) the destination, then [verify signatures](#verify-a-signature) on custom HTTPS endpoints.
3. [Inspect](#inspect-deliveries) attempt history and [replay](#replay-deliveries) failures when needed.
4. [Rotate the signing secret](#rotate-the-signing-secret) when credentials change.

## Requirements

Before you begin, authenticate to Dome and select a workspace.

### Permissions

Webhook operations require platform permissions. People and scoped API keys call the webhooks API. Agent credentials cannot.

Most roles can inspect subscriptions and deliveries. Creating destinations, rotating secrets, and changing subscriptions need `eventing.manage`. Replay re-sends requests to your systems and can trigger downstream automation, so it uses a separate `eventing.replay` permission.

| Default roles       | Permission        | Grants                                                                |
| ------------------- | ----------------- | --------------------------------------------------------------------- |
| All workspace roles | `eventing.view`   | List and inspect subscriptions, deliveries, providers                 |
| `admin`, `operator` | `eventing.manage` | Create, update, disable, delete, rotate secrets, test, cancel retries |
| `admin`, `operator` | `eventing.replay` | Single and bulk replay                                                |

## Create a subscription

Create a subscription and its destination atomically. A failed request leaves neither record behind. The response reveals the destination's `whsec_…` signing secret **once**. Store it before moving on. It is only rotatable afterward, never readable.

On the API, pass either `delivery_endpoint` (create a new destination) or `destination_id` (attach to an existing one). Never both. Standalone destination RPCs (`ListDestinations`, `CreateDestination`, `UpdateDestination`, `RotateDestinationSecret`, `DeleteDestination`) support shared-destination setups. CLI and MCP create the destination inline with the subscription. The dashboard can also pick an existing destination.

<Callout icon="key">Requires `eventing.manage`.</Callout>

Custom HTTPS endpoint:

```bash theme={"system"}
dome webhooks subscriptions create alerts \
  --url https://ops.example.com/hooks/dome \
  --event-type agent.suspended \
  --event-type authorization.rule_bundle.deployed
```

Slack via incoming-webhook URL:

```bash theme={"system"}
dome webhooks subscriptions create slack-alerts \
  --provider slack \
  --setting webhook_url=https://hooks.slack.com/services/T.../B.../XXXX \
  --event-type access.denied \
  --event-type agent.suspended
```

For provider-specific settings, credentials, shared destinations, MCP, and API examples, see the [webhooks CLI reference](/cli/operate/webhooks).

### Filters

You can narrow which events deliver. An event must satisfy every filter that applies to its type. A filter constrains only event types that carry its field.

Exact match

```bash theme={"system"}
dome webhooks subscriptions create prod-only \
  --url https://... --event-type agent.suspended \
  --filter 'agent_name=checkout-worker'
```

Glob pattern (`*` any run, `?` one char, full-value match)

```bash theme={"system"}
dome webhooks subscriptions create demo-tools \
  --url https://... --event-type mcp.tool_call.completed \
  --filter 'tool~=demo-mcp/*'
```

OR set (repeat the same key)

```bash theme={"system"}
dome webhooks subscriptions create critical-agents \
  --url https://... --event-type agent.suspended \
  --filter 'agent_name=checkout-worker' \
  --filter 'agent_name=billing-worker'
```

Filter keys: `agent_name`, `connection_name` (resolved from IDs at delivery time), `agent_id`, `tool_name`, plus each event type's own filterable payload fields. The dashboard Event catalog marks them. Repeated keys OR. Distinct keys AND. Caps: 16 keys, 16 alternatives per key, 256-byte patterns with up to 8 wildcards.

Per-request security decisions (`mcp.tool_call.completed`, `mcp.tool_result.filtered`, `llm.output.filtered`, `access.denied`) are high volume. Point them at a log sink rather than a chat channel, and narrow with filters.

## Test a subscription

Send a fixed `eventing.test` event through a subscription's destination to verify signing, headers, and the destination's own routing.

<Callout icon="key">Requires `eventing.manage`.</Callout>

<Tabs>
  <Tab title="CLI">
    ```bash theme={"system"}
    dome webhooks subscriptions test alerts
    ```

    The command prints the queued delivery ID. Check the outcome with `dome webhooks deliveries get <id>`.

    <Callout icon="terminal">Reference: [`dome webhooks subscriptions test`](/cli/operate/webhooks#subscriptions-test)</Callout>
  </Tab>

  <Tab title="MCP">
    Tool: `dome_webhooks_subscription_test`

    <Callout icon="cpu">Reference: [`dome_webhooks_subscription_test`](/reference/mcp/webhooks#subscription-test)</Callout>
  </Tab>

  <Tab title="Agent">
    ```text title="Test a webhook subscription" theme={"system"}
    Send a test event through the webhook subscription named alerts.
    ```
  </Tab>
</Tabs>

## Verify a signature

Verify custom HTTPS deliveries with any Standard Webhooks library. Return `2xx` within 10 seconds to acknowledge. Acknowledge first, process async. Slow handlers time out and burn retry budget.

<Tabs>
  <Tab title="Node.js">
    ```javascript theme={"system"}
    import { Webhook } from "standardwebhooks";

    const wh = new Webhook(process.env.DOME_WEBHOOK_SECRET); // whsec_...

    app.post("/webhooks/dome", express.raw({ type: "application/json" }), (req, res) => {
      try {
        const event = wh.verify(req.body, req.headers);
        // Dedupe on req.headers["dome-event-id"], then process async.
        res.status(202).send();
      } catch {
        res.status(400).send("invalid signature");
      }
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={"system"}
    from standardwebhooks.webhooks import Webhook

    wh = Webhook(os.environ["DOME_WEBHOOK_SECRET"])  # whsec_...

    @app.post("/webhooks/dome")
    def receive(request):
        try:
            event = wh.verify(request.body, dict(request.headers))
            # Dedupe on request.headers["dome-event-id"], then process async.
            return HttpResponse(status=202)
        except Exception:
            return HttpResponse(status=400)
    ```
  </Tab>
</Tabs>

## Inspect deliveries

Inspect delivery attempt history, including the retained body while it is available.

<Callout icon="key">Requires `eventing.view`.</Callout>

<Tabs>
  <Tab title="CLI">
    Failed deliveries in a time window:

    ```bash theme={"system"}
    dome webhooks deliveries list --status failed --start 2026-07-14T00:00:00Z
    ```

    One delivery with attempt history and the retained body:

    ```bash theme={"system"}
    dome webhooks deliveries get <delivery-id> --body
    ```

    <Callout icon="terminal">Reference: [`dome webhooks deliveries list`](/cli/operate/webhooks#deliveries-list), [`get`](/cli/operate/webhooks#deliveries-get)</Callout>
  </Tab>

  <Tab title="MCP">
    Tools: `dome_webhooks_delivery_list`, `dome_webhooks_delivery_get`.

    <Callout icon="cpu">Reference: [`dome_webhooks_delivery_list`](/reference/mcp/webhooks#delivery-list), [`dome_webhooks_delivery_get`](/reference/mcp/webhooks#delivery-get)</Callout>
  </Tab>

  <Tab title="Agent">
    ```text title="List failed webhook deliveries" theme={"system"}
    List failed webhook deliveries since 2026-07-14T00:00:00Z.
    ```
  </Tab>
</Tabs>

## Replay deliveries

Replay one delivery or bulk-replay failures in a window. A replay creates a **new** delivery from the retained body (fresh `webhook-id`, same `Dome-Event-Id`) so consumers that dedupe correctly ignore the overlap. Bulk replay processes up to 500 deliveries per run. Repeat to continue. Canceled deliveries are never recovered.

<Callout icon="key">Requires `eventing.replay`.</Callout>

<Tabs>
  <Tab title="CLI">
    Replay one delivery:

    ```bash theme={"system"}
    dome webhooks deliveries replay <delivery-id>
    ```

    Bulk-replay terminal failures from the last 24 hours:

    ```bash theme={"system"}
    dome webhooks deliveries replay-failed --since 24h
    ```

    Narrow by subscription and status:

    ```bash theme={"system"}
    dome webhooks deliveries replay-failed --since 7d --subscription alerts --status failed,dlq
    ```

    `replay-failed` prints `matched · replayed · skipped (body expired) · failed`. It is safe to re-run: deliveries with a live or succeeded replay are not matched again.

    <Callout icon="terminal">Reference: [`dome webhooks deliveries replay`](/cli/operate/webhooks#deliveries-replay), [`replay-failed`](/cli/operate/webhooks#deliveries-replay-failed)</Callout>
  </Tab>

  <Tab title="MCP">
    Tools: `dome_webhooks_delivery_replay`, `dome_webhooks_delivery_replay_failed`, `dome_webhooks_delivery_cancel`.

    ```json theme={"system"}
    {
      "name": "dome_webhooks_delivery_replay_failed",
      "arguments": { "since": "24h", "subscription": "alerts" }
    }
    ```

    <Callout icon="cpu">Reference: [`dome_webhooks_delivery_replay_failed`](/reference/mcp/webhooks#delivery-replay-failed)</Callout>
  </Tab>

  <Tab title="API">
    ```http theme={"system"}
    POST /dome.eventing.v1.EventingService/ReplayFailedDeliveries
    Content-Type: application/json

    {
      "workspace_id": "ws_...",
      "since": "2026-07-14T00:00:00Z",
      "destination_id": "dst_...",
      "statuses": ["failed", "dlq"],
      "max_deliveries": 500
    }
    ```

    The response returns `matched`, `replayed`, `skipped_body_expired`, and `failed` counts plus `replay_delivery_ids`. Also available: `ReplayDelivery`, `CancelDeliveryRetry`.

    <Callout icon="code">Reference: Eventing `ReplayFailedDeliveries` RPC</Callout>
  </Tab>

  <Tab title="Agent">
    ```text title="Replay failed webhook deliveries" theme={"system"}
    Replay all failed webhook deliveries from the last 24 hours.
    ```
  </Tab>
</Tabs>

## Rotate the signing secret

Rotate a destination's signing secret without dropping deliveries. For 24 hours, the `webhook-signature` header carries a signature per key (current first, previous second) so a consumer verifying with either secret keeps working. Update your verifier to the new secret within the 24-hour grace window.

<Callout icon="key">Requires `eventing.manage`.</Callout>

<Tabs>
  <Tab title="CLI">
    ```bash theme={"system"}
    dome webhooks subscriptions rotate-secret alerts
    ```

    The command prints the new signing secret once (`whsec_…`) with its key ID.

    <Callout icon="terminal">Reference: [`dome webhooks subscriptions rotate-secret`](/cli/operate/webhooks#subscriptions-rotate-secret)</Callout>
  </Tab>

  <Tab title="MCP">
    Tool: `dome_webhooks_subscription_rotate_secret`

    <Callout icon="cpu">Reference: [`dome_webhooks_subscription_rotate_secret`](/reference/mcp/webhooks#subscription-rotate-secret)</Callout>
  </Tab>

  <Tab title="Agent">
    ```text title="Rotate a webhook signing secret" theme={"system"}
    Rotate the signing secret for the webhook subscription named alerts.
    ```
  </Tab>
</Tabs>

## Next steps

* [Audit events](/operate/audit) for the durable record
* [Export Data](/manage/export) for scheduled batch export
* [Stream Live Events](/operate/observe) for live Audit v1 streaming
