Webhooks
Create a webhook endpoint
POST /v1/webhooks
- Scope
webhooks:write- Tier
- Tier 1
- Data
- Account data
- Idempotency
- Idempotency-Key: required
- Limit
- Up to 10 endpoints per account
The URL must be https:// and resolve to a public address. The answer is the only time the signing secret is shown: store it. secret is null only on a replayed answer (Idempotency-Replayed: true). DialerBee never stores the secret; if you lost it, rotate it. At most 10 endpoints per account.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | Your unique value for this logical operation (a UUID is fine). Scoped to your API client, kept 24 hours. (min length 1; max length 255) |
X-Correlation-ID | header | string | no | Your own trace value, logged with the request. Metadata only, never identity. (min length 1; max length 128) |
Request body
The endpoint.
JSON: WebhookEndpointCreateRequest
Response
201: The endpoint and its signing secret (shown once).
| 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. |
Idempotency-Replayed | true when this answer is the stored answer of an earlier request with the same Idempotency-Key. |
Examples
Request example
curl
curl -sS -X POST \
"https://app.dialerbee.com/api/v1/webhooks" \
-H "Authorization: Bearer $DIALERBEE_API_KEY" \
-H 'Idempotency-Key: 5f2b7c1e-8a3d-4c6f-9b0e-2d4a6c8e1f3a' \
-H "Content-Type: application/json" \
--data '{
"url": "https://crm.example.com/dialerbee/webhooks",
"events": [
"call.completed",
"disposition.logged"
],
"description": "CRM sync"
}'
Python (SDK)
from dialerbee import DialerBee
db = DialerBee() # reads DIALERBEE_API_KEY from the environment
result = db.webhooks.create(
url="https://crm.example.com/dialerbee/webhooks",
events=["call.completed", "disposition.logged"],
description="CRM sync",
idempotency_key="5f2b7c1e-8a3d-4c6f-9b0e-2d4a6c8e1f3a",
)
Response example
201
{
"id": "wh_0f8fad5b-d9cb-469f-a165-70867728950e",
"url_preview": "https://crm.example.com/dialerbee/...",
"host": "crm.example.com",
"description": "CRM sync",
"events": [
"call.completed"
],
"enabled": true,
"secret_hint": "safe",
"created_at": "2026-09-29T09:15:00Z",
"updated_at": "2026-09-29T09:20:00Z",
"secret": "whsec_EXAMPLE-shown-once-keep-it-safe"
}
Error examples
403 webhooks_disabled
{
"type": "https://docs.dialerbee.com/errors/webhooks-disabled",
"title": "Webhooks not enabled",
"status": 403,
"detail": "Webhooks are not switched on for this account.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "webhooks_disabled",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
409 webhook_limit_reached
{
"type": "https://docs.dialerbee.com/errors/webhook-limit-reached",
"title": "Webhook endpoint limit reached",
"status": 409,
"detail": "The account already has the maximum number of webhook endpoints (10).",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "webhook_limit_reached",
"request_id": "req_01K6BZ3M9X4T7Q2V8N5R6P1W0C"
}
422 webhook_url_refused
{
"type": "https://docs.dialerbee.com/errors/webhook-url-refused",
"title": "Webhook URL refused",
"status": 422,
"detail": "The webhook URL must be https://, must resolve to a public address, and must not point to a private, loopback, link-local or cloud-metadata address.",
"instance": "urn:dialerbee:request:req_01K6BZ3M9X4T7Q2V8N5R6P1W0C",
"code": "webhook_url_refused",
"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 | credential_in_body | Credential in body |
| 400, 422 | validation_failed | Invalid request |
| 413 | payload_too_large | Payload too large |
| 415 | unsupported_media_type | Unsupported media type |
| 400 | idempotency_key_required | Idempotency-Key required |
| 403 | webhooks_disabled | Webhooks not enabled |
| 409 | webhook_limit_reached | Webhook endpoint limit reached |
| 422 | webhook_url_refused | Webhook URL refused |
| 409 | conflict | Request in progress |
| 409 | idempotency_conflict | Idempotency key reused |
| 409 | outcome_unknown | Outcome unknown |
| 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
WebhookEndpointCreateRequest
| Field | Type | Required | Description |
|---|---|---|---|
url | string (uri) | yes | (min length 9; max length 2048; https only) |
events | array of one of call.completed, ai_call.completed, disposition.logged, appointment.booked, appointment.moved, appointment.cancelled | yes | (min items 1; max items 6) |
description | string | no | (max length 200) |
WebhookEndpointCreated
| Field | Type | Required | Description |
|---|---|---|---|
id | string (WebhookEndpointId) | yes | A webhook endpoint. wh_ + a lower-case UUID. |
url_preview | string | yes | The URL with its path and query shortened; the full URL is never shown again. |
host | string | yes | |
description | string | yes | |
events | array of one of call.completed, ai_call.completed, disposition.logged, appointment.booked, appointment.moved, appointment.cancelled | yes | |
enabled | boolean | yes | |
secret_hint | string | yes | The last four characters of the current secret. |
created_at | string (date-time) | yes | |
updated_at | string (date-time) | yes | |
secret | string or null | yes | The signing secret (whsec_...). Shown only in this answer: null only on a replayed answer (Idempotency-Replayed: true). DialerBee never stores the secret; if you lost it, rotate it. |