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

# Webhooks

> Receive DevHelm incident and event notifications via HTTP webhooks with optional HMAC signing

DevHelm supports two webhook systems:

1. **Alert channel webhooks** — incident notifications routed through notification policies (this page)
2. **Platform event webhooks** — subscribe to specific event types for broader automation (see [API Reference](/api-reference))

## Alert channel webhooks

Send incident notifications to any HTTP endpoint.

### Setup

<CodeGroup>
  ```bash CLI theme={null}
  devhelm alert-channels create \
    --name "Custom Webhook" \
    --type webhook \
    --config '{"channelType":"webhook","url":"https://your-app.example.com/webhooks/devhelm","signingSecret":"my-hmac-secret"}'
  ```

  ```yaml devhelm.yml theme={null}
  alertChannels:
    - name: Custom Webhook
      config:
        channelType: webhook
        url: https://your-app.example.com/webhooks/devhelm
        signingSecret: ${WEBHOOK_SIGNING_SECRET}
        customHeaders:
          X-Source: devhelm
  ```
</CodeGroup>

### Configuration

| Field           | Description                                  | Required |
| --------------- | -------------------------------------------- | -------- |
| `url`           | Webhook endpoint URL (HTTP or HTTPS)         | Yes      |
| `signingSecret` | HMAC signing secret for payload verification | No       |
| `customHeaders` | Additional HTTP headers to include           | No       |

<Note>
  Custom headers cannot use the `X-DevHelm-*` prefix or override `Content-Type`.
</Note>

### Verifying signatures

When a signing secret is configured, DevHelm includes a signature header:

```
X-DevHelm-Signature: t=1712956800;v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
```

To verify:

1. Extract the `t` (timestamp) and `v1` (signature) values
2. Compute `HMAC-SHA256(signingSecret, t + ":" + requestBody)`
3. Compare the computed signature with `v1`
4. Optionally reject requests where `t` is too old (replay protection)

The signed string uses a literal colon (`:`) between the timestamp and the raw request body — no
quoting, no escaping. Use the **raw bytes** of the HTTP request body (do not re-serialise the
parsed JSON, since key ordering or whitespace would change the hash).

## Platform event webhooks

For broader event coverage beyond incident notifications, use the platform webhook system at `/api/v1/webhooks`.

### Available event types

**Monitoring events:**

* `monitor.created`, `monitor.updated`, `monitor.deleted`
* `incident.created`, `incident.resolved`, `incident.reopened`

**Status data events:**

* `service.status_changed`, `service.component_changed`
* `service.incident_created`, `service.incident_updated`, `service.incident_resolved`

### Envelope format

Every platform event webhook delivery POSTs the following envelope as the request body:

```json theme={null}
{
  "id": "11111111-1111-1111-1111-111111111111",
  "type": "incident.created",
  "apiVersion": "2026-01",
  "createdAt": "2026-04-24T12:34:56Z",
  "data": {
    // Event-specific payload
  }
}
```

* `id` — unique event ID. Use this for **idempotent processing**: the same `id` is sent on every retry, so receivers can deduplicate by storing IDs they've already processed.
* `type` — event type identifier (matches the `X-DevHelm-Event` header).
* `apiVersion` — pinned envelope/payload version. Increments only when the schema changes incompatibly. Receivers should branch on this value if they need to support multiple versions during a migration.
* `createdAt` — UTC timestamp (ISO 8601 with `Z` suffix) of when DevHelm originated the event.
* `data` — the event-specific payload. Shape depends on `type`.

### Outgoing headers

| Header                | Description                           |
| --------------------- | ------------------------------------- |
| `X-DevHelm-Event`     | Event type (e.g., `incident.created`) |
| `X-DevHelm-Delivery`  | Unique delivery ID                    |
| `X-DevHelm-Signature` | `t=<timestamp>;v1=<hmac-sha256>`      |

### Managing webhook endpoints

```bash theme={null}
# Create a webhook endpoint
curl -X POST https://api.devhelm.io/api/v1/webhooks \
  -H "Authorization: Bearer $DEVHELM_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/events",
    "subscribedEvents": ["incident.created", "incident.resolved"]
  }'

# Test a webhook
curl -X POST https://api.devhelm.io/api/v1/webhooks/<id>/test \
  -H "Authorization: Bearer $DEVHELM_API_TOKEN"

# List deliveries
curl https://api.devhelm.io/api/v1/webhooks/<id>/deliveries \
  -H "Authorization: Bearer $DEVHELM_API_TOKEN"
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Webhook deliveries failing">
    1. Check that your endpoint returns a 2xx status code within the timeout
    2. Review delivery history: `GET /api/v1/webhooks/<id>/deliveries`
    3. Verify your endpoint accepts POST requests with `Content-Type: application/json`
  </Accordion>

  <Accordion title="Signature verification failing">
    1. Make sure you're using the correct signing secret
    2. Use the raw request body for HMAC computation (before any JSON parsing)
    3. The signature format is `t=<unix-timestamp>;v1=<hex-hmac>` — parse both values
  </Accordion>
</AccordionGroup>
