POST.
Quick start
- Create a webhook secret and store it securely.
- Register a webhook URL in the dashboard.
- Return a
2xxstatus code to theverificationrequest DialNexa sends the moment you save the URL. Until your endpoint does this, the webhook is not saved and no events are delivered. - Verify every incoming signature before processing events.
- Parse
event_typeand handle the event-specific payload.
Request format
Every webhook request has this high-level structure:event_type: The event name used for routing.payload: Event-specific data.
Supported event types
verification
Sent when you register a webhook URL, and again each time you change that URL. It is the first request your endpoint will ever receive from DialNexa, and the only event that is not tied to a call.
Your endpoint must respond with a 2xx status code within the request timeout configured on the webhook. If it responds with anything else, times out, or is unreachable, DialNexa does not save the webhook and no call events are ever delivered to it.
How this event differs from call events:
payloadis flat and contains nocallobject. Handlers that readpayload.call.idwithout a guard will throw on this request, which fails verification and blocks the webhook from being saved.- The
User-Agentheader isDialNexa-External-Webhook-Verification/1.0. Every other event usesDialNexa-External-Webhook/1.0. - Signature verification works exactly as described in Signature verification. The
x-dialnexa-signatureheader is present whenever your organization has a webhook secret, so create the secret before registering the URL if you want to test your signature check with this request. - Verification requests are not retried and do not appear in delivery logs. Retry settings apply only to call events.
call_initiated
Sent when a call starts.
call_ended with status: "hangup"
Sent when a call ends without completing.
The reason is in hangup_reason. It is always present on this event, and is also sent
as disconnection_reason, a deprecated alias carrying the identical value. Read
hangup_reason; treat disconnection_reason as legacy.
See Hangup reasons for every value and what it means.
call_ended with status: "completed"
Sent when a call completes. This payload can include transcript, summary, recording URL, and post-call analysis fields.
On this event hangup_reason tells you who ended the conversation, rather than why the
call failed. See Hangup reasons. Note it is not accompanied by a
disconnection_reason alias; that field appears only on the hangup variant above.
recording_url values are pre-signed links and expire after 7 days.transfer_completed
For conversational agents using a Transfer node, this event is emitted when handoff is processed.
call_ended (transferred calls)
Completed transferred calls can include an additional call_transfer object for transfer metadata.
Hangup reasons
Everycall_ended event carries hangup_reason. What it describes depends on the variant:
status: "completed": the call connected and a conversation happened, so the reason says who hung up first.status: "hangup": the call never reached a conversation, so the reason says why it did not connect.
Custom notes
Every call event carries anotes field inside payload.call. It returns whatever JSON object you attached to the call when you created it, unchanged, and is null when you attached nothing.
Use it to carry your own identifiers through the call and back, so your handler can match an event to a record on your side without keeping a lookup table of DialNexa call IDs.
Setting notes
How you attach notes depends on how the call is placed:
In a recipient or lead file, the
notes column is reserved: it becomes the call’s notes rather than a dynamic variable. A cell holding a JSON object is stored as that object. Plain text is wrapped as {"text": "..."}. A cell that starts with { or [ but is not valid JSON fails the upload with a 400 rather than being stored as text, so a malformed object is never silently flattened.
notes and metadata are separate fields with separate jobs. metadata is injected into the agent’s prompt as {{variables}} and shapes what the agent says; notes is inert storage that only your webhook handler sees. Data the agent must not read belongs in notes; though since notes are sent to your endpoint on every event for the call, they are not a place for credentials or secrets either.
Signature verification
Every webhookPOST includes an x-dialnexa-signature header.
DialNexa computes this value as an HMAC-SHA256 hex digest over the entire request body (the raw JSON bytes sent in the POST) using your webhook secret as the key.
Verification checklist
- Read the
x-dialnexa-signatureheader. - Read the raw request body as bytes (before JSON parsing).
- Compute
HMAC_SHA256(raw_request_body, WEBHOOK_SECRET). - Compare expected vs received signatures using a constant-time comparison.
- Reject on mismatch, then parse JSON and handle
event_typeandpayload.
Node.js example
Python example
Secret rotation
Rotating your webhook secret updates all webhooks in your organization immediately. The old secret is deactivated and the new secret takes effect right away.- Update your webhook server configuration to use the new secret before or immediately after rotation.
- Keep deployment steps ready to avoid signature mismatches during rollout.
- Validate signature checks in staging before rotating in production.