Webhooks
Be told when something happens, instead of asking.
A webhook endpoint is an organization-wide subscription to a list of events. Deliveries are signed with HMAC-SHA256 over `<timestamp>.<body>` and sent as `X-Vocalis-Signature: t=…,v1=…`; verify it before trusting a payload, and reject a timestamp that is not recent. Each delivery carries `X-Vocalis-Event-Id`, which is the same on every retry — use it as an idempotency key. Failures are retried with exponential backoff; a 4xx other than 408 or 429 is treated as a refusal and not retried, and an endpoint that fails continuously is switched off rather than being sent events into a void.
The signing secret is returned exactly once, when the endpoint is created and again when it is rotated. There is no endpoint that reads it back.
List endpoints
Every webhook endpoint in the organization.
/api/v1/webhook-endpointsResponses
{"data": {"endpoints": [{"id": "c41a…","name": "Ops receiver","url": "https://hooks.example.com/vocalis","events": ["call.ended","call.analysis.completed"],"secretPrefix": "whsec_9Qa3Kd","isEnabled": true,"consecutiveFailures": 0,"lastSuccessAt": "2026-09-15T13:58:02.000Z"}]},"meta": {"requestId": "req_…"}}
curl -X GET "https://voice.evryhealth.com/api/v1/webhook-endpoints" \-H "Authorization: Bearer YOUR_API_KEY"
Create an endpoint
Subscribe a URL to a list of events. The URL is checked at creation: it must be public http(s), and one resolving to a private or link-local address is refused.
/api/v1/webhook-endpointsResponses
{"data": {"id": "c41a…","name": "Ops receiver","url": "https://hooks.example.com/vocalis","events": ["call.ended","intelligence.speaker.identified"],"secret": "whsec_9Qa3Kd…","secretPrefix": "whsec_9Qa3Kd"},"meta": {"requestId": "req_…"}}
curl -X POST "https://voice.evryhealth.com/api/v1/webhook-endpoints" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "Ops receiver","url": "https://hooks.example.com/vocalis","events": ["call.ended","intelligence.speaker.identified"]}'
Get an endpoint
One endpoint. The signing secret is never returned here.
/api/v1/webhook-endpoints/{endpointId}Path parameters
| Parameter | Type | Description |
|---|---|---|
endpointIdrequired | string | Endpoint id. |
Responses
{"data": {"id": "c41a…","name": "Ops receiver","url": "https://hooks.example.com/vocalis","events": ["call.ended"],"secretPrefix": "whsec_9Qa3Kd","isEnabled": true},"meta": {"requestId": "req_…"}}
curl -X GET "https://voice.evryhealth.com/api/v1/webhook-endpoints/{endpointId}" \-H "Authorization: Bearer YOUR_API_KEY"
Update an endpoint
Change the URL, the subscription, or pause it. Re-enabling clears the failure count, so an endpoint switched off after an outage starts clean.
/api/v1/webhook-endpoints/{endpointId}Path parameters
| Parameter | Type | Description |
|---|---|---|
endpointIdrequired | string | Endpoint id. |
Responses
{"data": {"id": "c41a…","events": ["call.ended"]},"meta": {"requestId": "req_…"}}
curl -X PATCH "https://voice.evryhealth.com/api/v1/webhook-endpoints/{endpointId}" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"events": ["call.ended"],"isEnabled": true}'
Rotate the secret
Issue a new signing secret, effective immediately. There is no overlap window — an overlap is a period in which a leaked old secret still signs valid-looking traffic, and rotation usually happens because the old one leaked. Have the receiver ready for the new secret before calling this.
/api/v1/webhook-endpoints/{endpointId}/rotate-secretPath parameters
| Parameter | Type | Description |
|---|---|---|
endpointIdrequired | string | Endpoint id. |
Responses
{"data": {"id": "c41a…","secret": "whsec_2Pb7Xm…"},"meta": {"requestId": "req_…"}}
curl -X POST "https://voice.evryhealth.com/api/v1/webhook-endpoints/{endpointId}/rotate-secret" \-H "Authorization: Bearer YOUR_API_KEY"
Delivery log
What we tried to send, how many times, and what the receiver said. Payloads are not returned — they were sent to you, and they are encrypted at rest because they carry PHI.
/api/v1/webhook-endpoints/{endpointId}/deliveriesPath parameters
| Parameter | Type | Description |
|---|---|---|
endpointIdrequired | string | Endpoint id. |
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | pending, in_flight, succeeded, failed or dead_lettered. |
limit | number | Up to 200. Default: |
cursor | string | From meta.pagination.nextCursor. |
Responses
{"data": {"deliveries": [{"id": "7f21…","eventType": "call.ended","eventId": "1789525082142-0","status": "succeeded","attemptCount": 1,"responseStatus": 200,"createdAt": "2026-09-15T14:07:44.400Z"}]},"meta": {"requestId": "req_…","pagination": {"nextCursor": null,"limit": 50}}}
curl -X GET "https://voice.evryhealth.com/api/v1/webhook-endpoints/{endpointId}/deliveries" \-H "Authorization: Bearer YOUR_API_KEY"
Delete an endpoint
Stop delivering. Queued deliveries for it are abandoned rather than chased.
/api/v1/webhook-endpoints/{endpointId}Path parameters
| Parameter | Type | Description |
|---|---|---|
endpointIdrequired | string | Endpoint id. |
Responses
{"data": {"deleted": true},"meta": {"requestId": "req_…"}}
curl -X DELETE "https://voice.evryhealth.com/api/v1/webhook-endpoints/{endpointId}" \-H "Authorization: Bearer YOUR_API_KEY"