Skip to content

Webhook endpoints

Where we send events, and how each delivery went.

Every example sends your key ID and secret as CALLVIEW_KEY_ID and CALLVIEW_SECRET (see Keys and authentication). The base address is https://v2-api.callview.ai/api/v1/external.

POST /webhook_endpoints

Where we send events. HTTPS only, and the address must be on the public internet. The endpoint’s mode is the key’s: a test key’s endpoint gets test events only. The secret (whsec_…) is in this reply only. Every delivery is signed with it in the CallView-Signature header (see the Webhooks guide). At most 10 endpoints per organization. Needs webhooks:write, plus the read permission of every event’s data: leads:read for lead.created, lead.queued, lead.opted_out, lead.late and callback.booked; calls:read for call.*, lead.interested, handover.accepted and voicemail.left (403 permission_denied names the one missing).

Parameters

Name In Type Required Notes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
url string yes At most 2048 characters.
events array of string yes At most 50 items.
campaign_ids array of string (uuid) or null Only these campaigns. null or left out = every campaign (needs a key for every campaign).
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhookEndpoints-0001' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
]
}'

201 Created. Keep the secret; it is not shown again.

{
"data": {
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z",
"secret": "whsec_DO_NOT_USE_this_is_an_example_value"
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied, limit_reached
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

GET /webhook_endpoints

The endpoints for the key’s mode (test or live) within its campaigns. Needs webhooks:read.

Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 Your endpoints

{
"data": [
{
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z"
}
],
"meta": {
"next_cursor": null,
"has_more": false
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
429 rate_limited, too_many_concurrent_requests
500 internal_error

GET /webhook_endpoints/{id}

Needs webhooks:read. Another organization’s endpoint, or one of the other mode, is 404.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 The endpoint (never its secret)

{
"data": {
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z"
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

PATCH /webhook_endpoints/{id}

url, events, campaign_ids (null = every campaign) or status (active or paused). A new address is checked like a new endpoint’s. Needs webhooks:write; changing url, events or campaign_ids also needs the read permission of every event the endpoint takes (as at creation).

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
url string At most 2048 characters.
events array of string At most 50 items.
campaign_ids array of string (uuid) or null
status string One of active / paused.
Terminal window
curl -X PATCH 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: patchWebhookEndpointsId-0001' \
-H 'Content-Type: application/json' \
-d '{
"events": [
"call.completed",
"lead.interested",
"lead.opted_out"
]
}'

200 The changed endpoint

{
"data": {
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z"
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

DELETE /webhook_endpoints/{id}

The endpoint and its delivery history go. Events stay in GET /events. Needs webhooks:write.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Terminal window
curl -X DELETE 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 Deleted

{
"data": {
"id": "string",
"object": "string",
"deleted": true,
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

POST /webhook_endpoints/{id}/test

Sends one sample of any event type to this endpoint, so you can check your receiver. It is the event’s example in a real envelope with a new evt_ id, livemode false and “sample”: true, signed with this endpoint’s secret just like a real delivery, and retried like one. It shows in the endpoint’s deliveries. It is not an event, so GET /events doesn’t list it. A paused endpoint has to be resumed first. Needs webhooks:write.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
type string yes An event type, for example call.completed.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/test' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhookEndpointsIdTest-0001' \
-H 'Content-Type: application/json' \
-d '{
"type": "call.completed"
}'

202 Queued. It goes out within a second or two.

{
"data": {
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"object": "webhook_delivery",
"endpoint_id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"event_id": "evt_callcompletedxxxxxxxxxxx",
"event_type": "call.completed",
"status": "sent",
"attempts": 1,
"next_attempt_at": null,
"last_attempt_at": "2026-10-06T17:05:21.000Z",
"response_status": 200,
"response_body": "ok",
"duration_ms": 182,
"resent_from": null,
"created": "2026-10-06T17:05:20.000Z",
"livemode": true,
"event": {
"id": "string",
"type": "lead.created",
"created": "2026-10-06T17:05:20Z",
"livemode": true,
"api_version": "2026-10-01",
"data": {
"object": {}
},
"sample": true
}
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 endpoint_paused, idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

GET /webhook_endpoints/{id}/deliveries

Each delivery is one event sent (or waiting to be sent) to this endpoint: its status, how many tries (7 at most, over 24 hours), your last answer (the first 4 KB) and the times. Newest first, page by page (starting_after = the next_cursor you were given). Needs webhooks:read.

Parameters

Name In Type Required Notes
id path string (uuid) yes
limit query integer Default 25. 1 to 100.
starting_after query string (uuid)
status query string One of pending / sent / failed / gave_up / skipped_paused.
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/deliveries' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 A page of deliveries

{
"data": [
{
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"object": "webhook_delivery",
"endpoint_id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"event_id": "evt_callcompletedxxxxxxxxxxx",
"event_type": "call.completed",
"status": "sent",
"attempts": 1,
"next_attempt_at": null,
"last_attempt_at": "2026-10-06T17:05:21.000Z",
"response_status": 200,
"response_body": "ok",
"duration_ms": 182,
"resent_from": null,
"created": "2026-10-06T17:05:20.000Z",
"livemode": true
}
],
"meta": {
"next_cursor": null,
"has_more": false
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

POST /webhook_endpoints/{id}/deliveries/{delivery_id}/resend

A new delivery with the same event id (so your side can skip it if it already has it) and a fresh signature. A paused endpoint has to be resumed first. Needs webhooks:write.

Parameters

Name In Type Required Notes
delivery_id path string yes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/deliveries/5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a/resend' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhookEndpointsIdDeliveriesDeliveryIdResend-0001'

202 Queued. It goes out within a second or two.

{
"data": {
"id": "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
"object": "webhook_delivery",
"endpoint_id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"event_id": "evt_callcompletedxxxxxxxxxxx",
"event_type": "call.completed",
"status": "sent",
"attempts": 1,
"next_attempt_at": null,
"last_attempt_at": "2026-10-06T17:05:21.000Z",
"response_status": 200,
"response_body": "ok",
"duration_ms": 182,
"resent_from": null,
"created": "2026-10-06T17:05:20.000Z",
"livemode": true
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 endpoint_paused, idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

POST /webhook_endpoints/{id}/roll_secret

A new secret, shown once. The old one keeps signing too (two v1 values in the header) for grace_hours, so you can switch over without missing anything. Needs webhooks:write.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
grace_hours integer Default 24. 0 to 168.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/roll_secret' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhookEndpointsIdRollSecret-0001' \
-H 'Content-Type: application/json' \
-d '{
"grace_hours": 24
}'

200 The endpoint and its new secret

{
"data": {
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z",
"secret": "whsec_DO_NOT_USE_this_is_an_example_value"
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

POST /webhook_endpoints/{id}/resume

With resend_skipped true, the deliveries skipped while it was paused (up to 1,000, newest first) are sent again with their original event ids. Needs webhooks:write.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
resend_skipped boolean Default false.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhook_endpoints/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/resume' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhookEndpointsIdResume-0001' \
-H 'Content-Type: application/json' \
-d '{
"resend_skipped": true
}'

200 The endpoint, and how many deliveries were queued again

{
"data": {
"id": "3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b",
"object": "webhook_endpoint",
"url": "https://crm.example.com/callview",
"events": [
"call.completed",
"lead.interested"
],
"campaign_ids": null,
"mode": "live",
"livemode": true,
"status": "active",
"failing_since": null,
"paused_at": null,
"last_success_at": "2026-10-06T17:05:21.000Z",
"previous_secret_expires_at": null,
"created": "2026-10-01T09:00:00.000Z",
"updated": "2026-10-01T09:00:00.000Z",
"resent": 1
}
}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

GET /webhooks Old: still works, use the newer one

Replaced by GET /webhook_endpoints. Still answers its old shape, with a Deprecation header.

Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhooks' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 The old list

{}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
429 rate_limited, too_many_concurrent_requests
500 internal_error

POST /webhooks Old: still works, use the newer one

Replaced by POST /webhook_endpoints. Still answers its old shape, with a Deprecation header. The secret is in this reply only. Needs the read permission of every event’s data, as POST /webhook_endpoints does.

Parameters

Name In Type Required Notes
Idempotency-Key header string Any string you choose (1 to 255 visible characters), new for each new action. Send the same key again within 24 hours and you get the first answer back instead of a second lead or call. At most 255 characters.

Body

Field Type Required Notes
url string yes
events array of string yes
campaignId string (uuid) or null
enabled boolean Default true.
Terminal window
curl -X POST 'https://v2-api.callview.ai/api/v1/external/webhooks' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET" \
-H 'Idempotency-Key: postWebhooks-0001' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://crm.example.com/callview",
"events": [
"string"
],
"campaignId": "e4d3c2b1-a09f-4e8d-9c7b-6a5f4e3d2c1b",
"enabled": true
}'

201 Created

{}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied, limit_reached
409 idempotency_mismatch, idempotency_in_progress
429 rate_limited, too_many_concurrent_requests
500 internal_error
503 service_unavailable

DELETE /webhooks/{id} Old: still works, use the newer one

Replaced by DELETE /webhook_endpoints/{id}.

Parameters

Name In Type Required Notes
id path string (uuid) yes
Terminal window
curl -X DELETE 'https://v2-api.callview.ai/api/v1/external/webhooks/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 Deleted

{}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

GET /webhooks/{id}/deliveries Old: still works, use the newer one

Replaced by GET /webhook_endpoints/{id}/deliveries. A delivery’s payload is left out unless the key can read that event’s data (leads:read or calls:read, or events:read).

Parameters

Name In Type Required Notes
id path string (uuid) yes
limit query integer Default 25. 1 to 100.
Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhooks/3f6a9c2e-1b7d-4e5f-8a90-1c2d3e4f5a6b/deliveries' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 The deliveries

{}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
404 not_found
429 rate_limited, too_many_concurrent_requests
500 internal_error

GET /webhooks/events Old: still works, use the newer one

Every event type with a description and an example. The guide’s event reference has the same list.

Terminal window
curl -X GET 'https://v2-api.callview.ai/api/v1/external/webhooks/events' \
-u "$CALLVIEW_KEY_ID:$CALLVIEW_SECRET"

200 The catalog

{}

Errors

Status Codes
400 invalid_request
401 authentication_failed
403 permission_denied
429 rate_limited, too_many_concurrent_requests
500 internal_error