Webhook deliveries
Operations tagged Webhook deliveries in the public API.
About Webhook deliveries
A webhook delivery is one event on its way to one endpoint, with the outcome of its latest attempt. Delivery is at least once: dedupe on the event id (event_id, the Agentency-Event-Id header).
Lifecycle. A delivery is pending until its attempt is due (scheduled_at), processing while it is sent, and delivered once the endpoint answers 2xx within 10 seconds (redirects are not followed). A failed attempt puts it back to pending with a back-off of 1 minute, 5 minutes, 30 minutes, 2 hours, 5 hours and 10 hours; the seventh failed attempt — about 17.6 hours after the first — makes it failed. A delivery due to a disabled or deleted endpoint becomes failed at once, without a request. Deliveries are kept for 30 days by default.
Retry. POST /webhook_deliveries/{id}/retry re-queues a failed delivery with attempts reset: the same event, with the same evt_ id, to the same endpoint only. It records no new event. A delivered delivery is never sent again.
A key restricted to selected agents cannot read deliveries: 403 FORBIDDEN.
IDs you will meet.
id— the delivery id, an integer, fromGET /webhook_endpoints/{id}/deliveries.event_id— the event delivered (evt_…), forGET /events/{id}.endpoint_id— the endpoint it goes to.
IDs on this page
- Webhook delivery id
<DELIVERY_ID> - Integer. One per event and endpoint: the same event sent to two endpoints is two deliveries.
Get it from
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
data[].id - A delivery request carries no delivery id. To find the delivery behind one your receiver missed, list the endpoint's deliveries with
status=failedand matchevent_idto theAgentency-Event-Idyou expected.
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
Retrieve a webhook delivery
status, the attempts made, when the next one is due, and your endpoint's answer to the latest — status code, the first 512 characters of the body and the time it took.- Required scope
- webhooks:read
- Idempotency
- Read-only
- Rate limits
Integer. One per event and endpoint: the same event sent to two endpoints is two deliveries.id(path)Webhook delivery idPlaceholder in the samples:
<DELIVERY_ID>Get it from
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
data[].id - A delivery request carries no delivery id. To find the delivery behind one your receiver missed, list the endpoint's deliveries with
status=failedand matchevent_idto theAgentency-Event-Idyou expected.
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
Path parameters
idintegerRequiredThe webhook delivery id.
Responses
- 200
WebhookDeliveryResourceobjectstringRequiredAlways
webhook_deliveryidintegerRequiredThe delivery id.event_idstringRequiredThe event delivered (evt_…): theAgentency-Event-Idheader and the body'sid.endpoint_idintegerRequiredThe endpoint it goes to.event_typestringRequiredThe event's type, theAgentency-Event-Typeheader.Possible values
chatbot.createdchatbot.updatedchatbot.deletedchatbot.activatedchatbot.deactivatedknowledge.dataset.createdknowledge.dataset.trainedknowledge.dataset.failedknowledge.dataset.deletedcrawl.completedcrawl.failedconversation.startedconversation.message.createdconversation.endedconversation.handoff.requestedcustomer.createdcustomer.updatedlead.capturedaction.run.succeededaction.run.failedchannel.connectedchannel.disconnectedbilling.credits.lowbilling.credits.exhaustedbilling.subscription.updatedbilling.payment.failedbilling.trial.endingapi_key.createdapi_key.revokedwebhook_endpoint.disabledknowledge.collection.createdknowledge.collection.updatedknowledge.collection.deletedfile.createdfile.deletedcrawler.createdcrawler.updatedcrawler.deletedaction.createdaction.updatedaction.deletedcustomer.deletedwidget.updatedplugin.installedplugin.uninstalledprofile.updatedpingaction.form_submittedstatusstringRequiredpending(waiting for its next attempt),processing(being sent),delivered(the endpoint answered 2xx) orfailed(seven attempts failed, or its endpoint was disabled or deleted). Onlyfailedcan be retried.Possible values
pendingprocessingdeliveredfailedattemptsintegerRequiredAttempts made so far, at most 7. The next request'sAgentency-Delivery-Attemptheader is this plus one. A retry resets it to 0.scheduled_atstringnullableRequiredWhen the next attempt is due (ISO 8601, UTC); on adelivereddelivery, when its successful attempt was due;nulloncefailed.processed_atstringnullableRequiredWhen the delivery becamedeliveredorfailed(ISO 8601, UTC);nulluntil then.response_statusintegernullableRequiredThe HTTP status your endpoint answered the latest attempt with;nullbefore the first answer, or when none came (timeout, refused connection).response_body_snippetstringnullableRequiredThe first 512 characters of your endpoint's latest answer body;nullwhen there was none.duration_msintegernullableRequiredHow long the latest attempt took, in milliseconds;nullbefore the first.created_atstringnullableRequiredWhen the delivery was queued: when the event was recorded, or when a test ping was sent (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither.Error codesACCOUNT_SELECTOR_NOT_SUPPORTED
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDFORBIDDENINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X GET 'https://api.agentency.com/v1/webhook_deliveries/<DELIVERY_ID>' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "webhook_delivery",
"id": 1,
"event_id": "evt_example",
"endpoint_id": 1,
"event_type": "ping",
"status": "pending",
"attempts": 0,
"scheduled_at": "2026-01-01T00:00:00+00:00",
"processed_at": null,
"response_status": null,
"response_body_snippet": null,
"duration_ms": null,
"created_at": "2026-01-01T00:00:00+00:00"
}Retry a failed webhook delivery
failed delivery with attempts reset to 0 and returns it pending: the same event — same evt_ id and body — to the same endpoint only, with the full retry schedule again. It records no new event. Re-enable a disabled endpoint first, or the retry fails again without a request.
A delivery still pending or processing is 409 DELIVERY_IN_FLIGHT; a delivered one is 409 DELIVERY_ALREADY_DELIVERED and is never sent twice. Shares a budget of 20 calls a minute per API key with test pings.- Required scope
- webhooks:write
- Idempotency
- Accepts Idempotency-Key
- Webhook events
- None
- Rate limits
Integer. One per event and endpoint: the same event sent to two endpoints is two deliveries.id(path)Webhook delivery idPlaceholder in the samples:
<DELIVERY_ID>Get it from
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
data[].id - A delivery request carries no delivery id. To find the delivery behind one your receiver missed, list the endpoint's deliveries with
status=failedand matchevent_idto theAgentency-Event-Idyou expected.
- GET /v1/webhook_endpoints/{id}/deliveries returns it as
Path parameters
idintegerRequiredThe webhook delivery id.
Header parameters
Idempotency-KeystringOptionalMakes a retry safe. The first 2xx answer is stored for 24 h and replayed for the same key withIdempotency-Replayed: true; a retry while the first request runs is 409IDEMPOTENCY_IN_FLIGHT; the same key with a different payload is 422IDEMPOTENCY_KEY_REUSED; a malformed key is 400INVALID_IDEMPOTENCY_KEY.Min length:
16Max length:128Pattern:^[A-Za-z0-9_-]+$
Responses
- 200
WebhookDeliveryResourceobjectstringRequiredAlways
webhook_deliveryidintegerRequiredThe delivery id.event_idstringRequiredThe event delivered (evt_…): theAgentency-Event-Idheader and the body'sid.endpoint_idintegerRequiredThe endpoint it goes to.event_typestringRequiredThe event's type, theAgentency-Event-Typeheader.Possible values
chatbot.createdchatbot.updatedchatbot.deletedchatbot.activatedchatbot.deactivatedknowledge.dataset.createdknowledge.dataset.trainedknowledge.dataset.failedknowledge.dataset.deletedcrawl.completedcrawl.failedconversation.startedconversation.message.createdconversation.endedconversation.handoff.requestedcustomer.createdcustomer.updatedlead.capturedaction.run.succeededaction.run.failedchannel.connectedchannel.disconnectedbilling.credits.lowbilling.credits.exhaustedbilling.subscription.updatedbilling.payment.failedbilling.trial.endingapi_key.createdapi_key.revokedwebhook_endpoint.disabledknowledge.collection.createdknowledge.collection.updatedknowledge.collection.deletedfile.createdfile.deletedcrawler.createdcrawler.updatedcrawler.deletedaction.createdaction.updatedaction.deletedcustomer.deletedwidget.updatedplugin.installedplugin.uninstalledprofile.updatedpingaction.form_submittedstatusstringRequiredpending(waiting for its next attempt),processing(being sent),delivered(the endpoint answered 2xx) orfailed(seven attempts failed, or its endpoint was disabled or deleted). Onlyfailedcan be retried.Possible values
pendingprocessingdeliveredfailedattemptsintegerRequiredAttempts made so far, at most 7. The next request'sAgentency-Delivery-Attemptheader is this plus one. A retry resets it to 0.scheduled_atstringnullableRequiredWhen the next attempt is due (ISO 8601, UTC); on adelivereddelivery, when its successful attempt was due;nulloncefailed.processed_atstringnullableRequiredWhen the delivery becamedeliveredorfailed(ISO 8601, UTC);nulluntil then.response_statusintegernullableRequiredThe HTTP status your endpoint answered the latest attempt with;nullbefore the first answer, or when none came (timeout, refused connection).response_body_snippetstringnullableRequiredThe first 512 characters of your endpoint's latest answer body;nullwhen there was none.duration_msintegernullableRequiredHow long the latest attempt took, in milliseconds;nullbefore the first.created_atstringnullableRequiredWhen the delivery was queued: when the event was recorded, or when a test ping was sent (ISO 8601, UTC).
- 400A tenant selector header named a tenant other than the API key's own (
ACCOUNT_SELECTOR_NOT_SUPPORTED): an all-digitX-Account-Idother than the key owner's id or, whileworkspaces.context_enabledis on, anX-Workspace-Idother than the key's workspace (ws_prefix optional, case-insensitive). A header naming the key's own tenant, or a non-numericX-Account-Id, is ignored; a key cannot switch tenants, so send neither. A mutation that honoursIdempotency-Keyalso returnsINVALID_IDEMPOTENCY_KEYwhen that header is not 16–128[A-Za-z0-9_-]characters.Error codesACCOUNT_SELECTOR_NOT_SUPPORTEDINVALID_IDEMPOTENCY_KEY
- 401Missing or invalid API key.
Error codesUNAUTHENTICATED
- 403The API key is missing a required scope.
Error codesACCOUNT_SUSPENDEDFORBIDDENINSUFFICIENT_SCOPE
- 404The resource does not exist on this account.
Error codesNOT_FOUND
- 409The request conflicts with the current resource state.
Error codesDELIVERY_ALREADY_DELIVEREDDELIVERY_IN_FLIGHTIDEMPOTENCY_IN_FLIGHT
- 422Validation failed. See
error.details.Error codesIDEMPOTENCY_KEY_REUSED
- 429Rate limited. Honour the Retry-After header before retrying.
Error codesRATE_LIMITED
- 500Unexpected server error. Retry with the same Idempotency-Key.
Error codesSERVER_ERROR
Request
curl -X POST 'https://api.agentency.com/v1/webhook_deliveries/<DELIVERY_ID>/retry' \
-H "Authorization: Bearer <YOUR_KEY>" \
-H "Content-Type: application/json"Response
Example 200 response
{
"object": "webhook_delivery",
"id": 1,
"event_id": "evt_example",
"endpoint_id": 1,
"event_type": "knowledge.dataset.trained",
"status": "pending",
"attempts": 0,
"scheduled_at": "2026-01-01T00:00:00+00:00",
"processed_at": null,
"response_status": 503,
"response_body_snippet": "Service Unavailable",
"duration_ms": 412,
"created_at": "2026-01-01T00:00:00+00:00"
}