What a Finished Call Sends You
The rest of this section covers webhooks pointing into Dialora — you send a request, Dialora starts a call. This page covers the other direction: when a call finishes, Dialora sends the result to a URL of your choosing.
You get one either by setting webhook_url when you start a call through the API, or by adding the
Generic Webhook tool to your agent.
The request
A POST with a JSON body, and these headers:
| Header | Value |
|---|---|
Content-Type | application/json |
X-Dialora-Event | The event type, e.g. call.completed |
X-Dialora-Signature | Present when you set a webhook secret — see signing |
Respond with any 2xx status. Dialora retries up to two more times on a failure or timeout.
Event types
| Type | When |
|---|---|
call.completed | The call finished normally |
call.failed | The call could not be completed |
call.busy | The line was busy |
call.no_answer | Nobody picked up |
call.canceled | The call was canceled before connecting |
The payload
{
"id": "evt_9f2c7b1e-4a55-4a0b-9d3e-1c8a6f0b2d47",
"type": "call.completed",
"created_at": "2026-09-02T14:31:07.412Z",
"data": {
"id": "exec_8xk2m4p9q1",
"account_id": "acc_3nf7t2",
"agent_id": "agent_ylk6upw5obl8",
"agent_name": null,
"campaign_id": null,
"direction": "inbound",
"status": "completed",
"from_number": "+14155550142",
"to_number": "+18005550199",
"duration_seconds": 96,
"metadata": null,
"summary": "Caller booked a consultation for the 9th and gave a callback number.",
"transcript": "assistant: Thanks for calling…\nuser: Hi, I'd like to book…",
"extracted_data": {
"customer_name": "Alex Chen",
"contact_number": "+18896335677",
"preferred_date": "2026-09-09",
"party_size": 4,
"wants_callback": true,
"email_address": null
},
"hangup_by": "callee",
"hangup_reason": "completed",
"call_type": "telephony",
"created_at": "2026-09-02T14:29:31.008Z",
"updated_at": "2026-09-02T14:31:07.402Z"
}
}Fields
| Field | Notes |
|---|---|
id (envelope) | Unique per event. Use it to make your handler idempotent — a retry reuses it. |
type | One of the event types above |
data.id | The call’s own id |
agent_name | Always null in webhooks. Key off agent_id. |
campaign_id | Set when the call came from a campaign, otherwise null |
direction | inbound or outbound |
duration_seconds | null if the call never connected |
metadata | Whatever you passed when starting the call, otherwise null |
summary, transcript | null until they are available |
extracted_data | What your agent captured — see below |
What is inside extracted_data
The keys are the field names you chose when you set up data capture. The values match the kind of answer you picked for each field:
| Field kind | Value in the payload |
|---|---|
| Text, Choice | A string |
| Number, Whole number | A number, not a quoted string |
| Yes / No | true or false |
| Date | "2026-09-09" |
| Date & time | "2026-09-09T14:30" |
| Email address | A cleaned-up address |
| Phone number | International format, e.g. "+18896335677" |
| Website link | A full URL |
If the caller never gave an answer, or gave one that was never confirmed, its value is null — not a placeholder, not
an empty string, not a zero. Check for null rather than for falsiness, so a genuine 0 or false is not mistaken
for a missing answer.
Agents still using the original free-text capture setup send every value as a string, and send the literal text
DOESN'T EXIST where nothing was captured. If you handle calls from both, treat that string as missing. Switching an
agent over removes the need to.
extracted_data is null as a whole when the agent captures nothing at all.
Verifying the request
When you set a webhook secret, Dialora signs the body:
X-Dialora-Signature: t=1787660000,v1=<hex>v1 is an HMAC-SHA256 of "{t}.{raw body}" using your secret. Compute the same value over the raw
body — before any JSON parsing — and compare.
Next steps
- Capturing data from your calls — choosing what to record
- Troubleshooting common issues
- Best practices