---
updatedAt: 2026-08-18T17:22:08.000Z
agentTools:
  projectIndex: https://docs.checkhq.com/llms.txt
---

# Managing webhook configs and deliveries

Set up where Check sends webhooks and observe what was sent

Two API resources let you operate your webhook integration end to end:

* **[Webhook configs](https://docs.checkhq.com/reference/the-webhook-config-object)** define *where* Check sends webhooks — the endpoints you register, each with a signing key.
* **[Webhook deliveries](https://docs.checkhq.com/reference/the-webhook-delivery-object)** record *what* Check sent — every webhook we generated for your provider, its delivery status, and the attempts we made to deliver it.

Together they answer the two operational questions every webhook integration eventually hits: "is Check sending to the right place?" and "did the webhook I expected actually get delivered — and if not, why?"

Both objects are also available through the **Check MCP server**, so you — or an AI coding agent — can inspect webhook configs and query deliveries directly from your editor or terminal while debugging an integration.

## Setting up a webhook config

Register an endpoint with [`POST /webhook_configs`](https://docs.checkhq.com/reference/create-a-webhook-config):

```bash
curl https://api.checkhq.com/webhook_configs \
  -X POST \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/check/webhooks"}'
```

The response includes a generated `key`. Check signs every webhook request with it, and your handler should recompute the signature to verify authenticity — see [The Shape of Your Webhook Endpoint](https://docs.checkhq.com/docs/the-shape-of-your-webhook-endpoint) for the verification recipe, along with retry, ordering, and idempotency guidance.

A few things to know about configs:

* **Multiple configs are supported.** Every active config receives every webhook, so you can register a second endpoint to cut over gradually or to fan out to a separate consumer.
* **`active` controls sending.** Set it to `false` with [`PATCH /webhook_configs/{id}`](https://docs.checkhq.com/reference/update-a-webhook-config) to pause sending without losing the config (or its key). Note that webhooks generated while a config is inactive are not sent later — pausing means missing, not queueing.
* **`api_version` pins payload shape.** Set it on create or update to serialize webhook event payloads at a specific Check API version. When `null`, payloads follow your account's default API version. See [Versioning](https://docs.checkhq.com/reference/versioning) for supported version labels.
* **Check may disable a dead endpoint.** If an endpoint does nothing but fail for an extended period, Check can mark the config inactive. Monitor your [delivery statuses](#understanding-delivery-status) to catch problems before that happens.

To confirm an endpoint is wired up, send a test webhook with [`POST /webhook_configs/{id}/ping`](https://docs.checkhq.com/reference/ping-a-webhook-config). It delivers a `ping`-topic webhook through the same pipeline as real traffic, so it exercises your signature verification too.

## Observing deliveries

[`GET /webhook_deliveries`](https://docs.checkhq.com/reference/list-webhook-deliveries) returns every webhook Check generated for your provider, newest first, with cursor-based pagination (default page size 25, maximum 100):

```json
{
  "id": "whe_7uCODm8JFmZyov9jL8QO",
  "webhook_config": "whc_7uCODm8JFmZyov9jL8QO",
  "company": "com_zH8Gq33iBkFj5o0GKjTw",
  "topic": "payroll",
  "status": "delivered",
  "created_at": "2024-01-19T17:04:15Z",
  "attempts": [
    { "status_code": 200, "created_at": "2024-01-19T17:04:15Z" }
  ]
}
```

Filters combine with `AND`:

* `webhook_config` — deliveries sent to one of your configs.
* `company` — deliveries associated with a company.
* `topic` — a [webhook topic](https://docs.checkhq.com/docs/webhook-event-types); an invalid topic returns a validation error rather than an empty list.
* `status` — one of the delivery statuses below.
* `created_after` / `created_before` — an ISO-8601 time range.

For example, to find this morning's failed payroll webhooks:

```bash
curl -G https://api.checkhq.com/webhook_deliveries \
  -H "Authorization: Bearer <API_KEY>" \
  --data-urlencode "topic=payroll" \
  --data-urlencode "status=failed" \
  --data-urlencode "created_after=2026-08-11T00:00:00Z"
```

Deliveries intentionally do not include the webhook payload. The payload's home is the webhook request itself; when you need current state, fetch the resource — the payload reflects the resource at generation time and may already be stale by the time you read it (see [Working with Webhooks](https://docs.checkhq.com/docs/working-with-webhooks)).

## Understanding delivery status

Each delivery's `status` is derived from the delivery attempts made so far:

| Status      | Meaning                                                                                  |
| ----------- | ---------------------------------------------------------------------------------------- |
| `pending`   | Generated, first attempt not yet made.                                                   |
| `retrying`  | At least one attempt failed; Check is still retrying on an exponential backoff schedule. |
| `delivered` | Your endpoint returned a `2xx`.                                                          |
| `failed`    | All attempts were exhausted without a `2xx`.                                             |

The embedded `attempts` array (newest first) shows each attempt's `status_code` — the HTTP status your endpoint returned. A `null` `status_code` means no HTTP response was received at all: the request timed out, TLS negotiation failed, or the connection could not be established. A long run of `null` attempts usually means your endpoint is unreachable rather than erroring.

## Debugging a webhook problem

A typical investigation, using only these two APIs:

1. **Did Check generate the webhook?** List deliveries filtered by `topic` (and `company` if relevant) around the expected time. No delivery means the event didn't occur — check the resource itself.
2. **Was it delivered?** Look at `status`. A `delivered` webhook that your system didn't process points at your handler (check your own request logs for the delivery's `id` — it's sent in the `Check-WebhookEvent-ID` header).
3. **Why did it fail?** Read `attempts`. Consistent `5xx`s are your handler erroring; `401`/`403` suggests a signature or auth mismatch; `null` status codes mean Check couldn't reach the endpoint at all.
4. **Re-test after fixing.** In the sandbox environment, re-enqueue a delivery with [`POST /webhook_deliveries/{id}/retry`](https://docs.checkhq.com/reference/retry-a-webhook-delivery-in-sandbox) — it requires an `X-Idempotency-Key` header and an active webhook config, and returns a `400` in the live environment. In production, Check's automatic retry schedule handles redelivery; once your endpoint recovers, `retrying` deliveries will drain on their own.