Overview#
A delivery attempt is one HTTP request to one subscription. Where an event tells you what the platform raised, an attempt tells you what happened when it was sent: what went out, what came back, how long it took, and when the next try is due. This page covers searching attempts and reading one in full.Key features#
The request as sent: request_headers carries the signature headers that went out, so you can reproduce the check locally
The response as received: response_body_snippet holds the first 1024 bytes your endpoint returned
Timing: latency_ms measures your handler against the 30 second read timeout
The retry schedule: next_retry_at names the moment the next attempt is due
The run in order: attempt_number counts attempts for one event on one subscription
Sorting that fits the job: by attempt_number and latency_ms as well as the usual timestamps
Use cases#
Find out why a delivery your endpoint never logged was recorded as failed
Confirm what your endpoint actually returned, rather than what you expect it returned
Measure handler latency against the read timeout before it starts costing you deliveries
Walk from a failed attempt back to its event, then replay it
Prerequisites#
The paging and filtering contract shared by every search endpoint. See the API Basics. API#
Search Webhook Delivery Attempts
POST /api/v1/webhooks/delivery-attempts/searchPaginated search, usually filtered to one event's attempts.Get Webhook Delivery Attempt
GET /api/v1/webhooks/delivery-attempts/{attempt_id}One attempt in full, including the headers sent and the body returned.Send a filters object holding webhook_event_ids and you get back that event's attempts. The item route takes the integer id from a search row.
Business rules#
An attempt status is not an event status. An attempt is success, failed, timeout, or pending_retry. The event it belongs to is delivered, partially_delivered, failed, or dead_letter.
A timeout carries no http_status_code. The request never completed. latency_ms reports the read timeout instead of a real measurement.
response_body_snippet is truncated at 1024 bytes, and is empty when your endpoint returned nothing.
next_retry_at is set only while the attempt is pending_retry. In every other state it is empty, including on the final failed attempt.
X-Webhook-Delivery-Id is unique for every attempt. Deduplicate on the evt_ id inside the payload.
Retry counts, the backoff schedule, and the timeouts are the same for every subscription and are documented once in the Webhooks Guide.If a search returns an empty page while you know deliveries were made, do not assume the attempts were lost. Contact support with the event id and we will confirm what was recorded.
Errors#
Every error below returns the platform envelope, with error first and error_id last. Quote error_id when you contact support.| HTTP | code | Trigger | What you do |
|---|
| 422 | VALIDATION_FAILED | A filter was sent as a single value rather than a list, an unknown filter key was sent, or sort_by is outside id, created_at, updated_at, attempt_number, latency_ms | Read error.json for the field. Send every filter as a list. |
| 404 | NOT_FOUND | No attempt matches the id, or it belongs to another organisation | Take the id from a search result. |
| 401 | | The Authorization header is missing, malformed, or the token has expired | Request a new token and retry. The body is { "message": "Unauthorized" }. |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests | Back off and retry. |
| 500 | INTERNAL_ERROR | The platform failed to answer | Retry once, then contact support with error_id. |
Webhooks Guide
Signature verification, retry behaviour, and every event payload.Webhook Subscriptions Guide
The endpoints these attempts were made against.Support & Contact
What to send us when deliveries stop arriving.