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 define where Check sends webhooks — the endpoints you register, each with a signing key.
- Webhook deliveries 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:
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 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.
activecontrols sending. Set it tofalsewithPATCH /webhook_configs/{id}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.- 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 to catch problems before that happens.
To confirm an endpoint is wired up, send a test webhook with POST /webhook_configs/{id}/ping. 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 returns every webhook Check generated for your provider, newest first, with cursor-based pagination (default page size 25, maximum 100):
{
"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; 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:
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).
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:
- Did Check generate the webhook? List deliveries filtered by
topic(andcompanyif relevant) around the expected time. No delivery means the event didn't occur — check the resource itself. - Was it delivered? Look at
status. Adeliveredwebhook that your system didn't process points at your handler (check your own request logs for the delivery'sid— it's sent in theCheck-WebhookEvent-IDheader). - Why did it fail? Read
attempts. Consistent5xxs are your handler erroring;401/403suggests a signature or auth mismatch;nullstatus codes mean Check couldn't reach the endpoint at all. - Re-test after fixing. In the sandbox environment, re-enqueue a delivery with
POST /webhook_deliveries/{id}/retry— it requires anX-Idempotency-Keyheader and an active webhook config, and returns a400in the live environment. In production, Check's automatic retry schedule handles redelivery; once your endpoint recovers,retryingdeliveries will drain on their own.
Updated about 11 hours ago

