Webhooks
List webhook events
GET /v1/webhook-events
- Scope
webhooks:read- Tier
- Tier 1
- Data
- Account data
- Idempotency
- Idempotency-Key: not used
- Limit
- Up to 100 per page (default 50)
Events of the last 30 days, newest first, each with its deliveries. Delivery is at least once: de-duplicate on the event id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
limit | query | integer | no | (min 1; max 100; default 50) |
cursor | query | string | no | page.next_cursor from the previous page. Opaque; bound to your account, API client and filters. (min length 1; max length 1024) |
type | query | one of call.completed, ai_call.completed, disposition.logged, appointment.booked, appointment.moved, appointment.cancelled, webhook.test | no | |
webhook_id | query | string (WebhookEndpointId) | no | |
X-Correlation-ID | header | string | no | Your own trace value, logged with the request. Metadata only, never identity. (min length 1; max length 128) |
Response
200: One page of events.
| Header | Meaning |
|---|---|
X-Request-ID | The DialerBee request id. Quote it to support. Every response carries X-Request-ID: req_<ULID>, or edge_<32 hex> when the edge answered before the request reached the API. |
Cache-Control | Always no-store. |
Examples
Request example
curl
curl -sS -X GET \
"https://app.dialerbee.com/api/v1/webhook-events?limit=50" \
-H "Authorization: Bearer $DIALERBEE_API_KEY"
Python (SDK)
from dialerbee import DialerBee
db = DialerBee() # reads DIALERBEE_API_KEY from the environment
page = db.webhook_events.list(limit=50)
for item in page: # this page, then every following page
print(item.id)
Response example
200
{
"data": [
{
"id": "evt_0f8fad5b-d9cb-469f-a165-70867728950e",
"type": "call.completed",
"created_at": "2026-09-29T09:15:00Z",
"api_version": "v1",
"schema_version": 1,
"deliveries": [
{
"id": "whd_0f8fad5b-d9cb-469f-a165-70867728950e",
"webhook_id": "wh_0f8fad5b-d9cb-469f-a165-70867728950e",
"status": "delivered",
"attempts": 1,
"replay_of": null,
"last_status_code": 200,
"last_attempt_at": "2026-09-29T11:58:00Z",
"next_attempt_at": "2026-09-30T10:00:00Z",
"delivered_at": "2026-09-29T12:00:02Z",
"failure_reason": null,
"created_at": "2026-09-29T09:15:00Z"
}
]
}
],
"page": {
"next_cursor": "c1.example-opaque-cursor",
"has_more": true
}
}
Error examples
400 invalid_cursor
{
"type": "https://docs.dialerbee.com/errors/invalid-cursor",
"title": "Invalid cursor",
"status": 400,
"detail": "The cursor is not valid for this request: it was changed, it belongs to another list or other filters, or it expired.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "invalid_cursor",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
403 insufficient_scope
{
"type": "https://docs.dialerbee.com/errors/insufficient-scope",
"title": "Not permitted",
"status": 403,
"detail": "The API client does not hold the scope this operation requires.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "insufficient_scope",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
401 invalid_api_key
{
"type": "https://docs.dialerbee.com/errors/invalid-api-key",
"title": "Invalid API key",
"status": 401,
"detail": "The Authorization header is missing, is not Bearer dbk_live_..., or the key is not recognised, has expired or was revoked (one answer for every key problem, so a key's state is never revealed).",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "invalid_api_key",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
Errors
| Status | Code | Title |
|---|---|---|
| 401 | invalid_api_key | Invalid API key |
| 403 | api_access_disabled | API access disabled |
| 403 | ip_not_allowed | IP address not allowed |
| 403 | insufficient_scope | Not permitted |
| 400 | credential_in_url | Credential in URL |
| 400, 422 | validation_failed | Invalid request |
| 400 | invalid_cursor | Invalid cursor |
| 429 | rate_limit_exceeded | Too many requests |
| 503 | temporarily_unavailable | Temporarily unavailable |
| 503 | upstream_unavailable | Temporarily unavailable |
| 502 | upstream_invalid_response | Upstream error |
| 500 | internal_error | Internal error |
Objects
WebhookEventList
| Field | Type | Required | Description |
|---|---|---|---|
data | array of WebhookEvent | yes | |
page | Page | yes | Pass next_cursor as cursor to get the next page. null means this is the last page. |
Page
Pass next_cursor as cursor to get the next page. null means this is the last page.
| Field | Type | Required | Description |
|---|---|---|---|
next_cursor | string or null | yes | (max length 1024) |
has_more | boolean | yes |
WebhookEvent
| Field | Type | Required | Description |
|---|---|---|---|
id | string (WebhookEventId) | yes | A webhook event. Retries and replays keep the same event id. evt_ + a lower-case UUID. |
type | one of call.completed, ai_call.completed, disposition.logged, appointment.booked, appointment.moved, appointment.cancelled, webhook.test | yes | |
created_at | string (date-time) | yes | |
api_version | one of v1 | yes | |
schema_version | integer | yes | (min 1) |
deliveries | array of WebhookDelivery | yes |
WebhookDelivery
| Field | Type | Required | Description |
|---|---|---|---|
id | string (WebhookDeliveryId) | yes | One delivery of an event to one endpoint. A replay is a new delivery. whd_ + a lower-case UUID. |
webhook_id | string (WebhookEndpointId) | yes | A webhook endpoint. wh_ + a lower-case UUID. |
status | one of pending, retry_scheduled, delivered, failed, cancelled | yes | |
attempts | integer | yes | |
replay_of | string (WebhookDeliveryId) or null | yes | |
last_status_code | integer or null | yes | |
last_attempt_at | string (date-time) or null | yes | |
next_attempt_at | string (date-time) or null | yes | |
delivered_at | string (date-time) or null | yes | |
failure_reason | string or null | yes | Why the delivery stopped being retried, if it did. |
created_at | string (date-time) | yes |