Payload shape
Every call.completed delivery has the same top-level shape.
{
"event": "call.completed",
"created_at": "2026-09-18T11:14:09.000Z",
"data": { }
}
| Field | Type | Notes |
|---|---|---|
event | string | One of the events below. Check it before you read data. |
created_at | ISO 8601 | When Finn built the payload, not when it was delivered. |
data | object | Details for the event. |
There's no event ID. To remove duplicates, use event plus data.call_uuid as the key. The event name also arrives in the X-Finn-Event header. See webhook-security to verify signatures and webhook-retries for the delivery schedule.
Event catalog
| Event | Fires when |
|---|---|
call.completed | A call in your organization has ended, answered or not. For an answered call on a Finn with post-call analysis fields, Finn waits for the analysis first. Each endpoint gets it at most once per call. |
call.completed is the only event Finn sends. Every endpoint is subscribed to it.
A Finn's Data webhook URL and Inbound webhook URL can also receive a test request, post_call.test or inbound_call.test, when someone clicks Initialize next to the URL in Deployment settings. It isn't a real event and has a different body, with no data. Return 2xx and ignore it. See webhooks.
call.completed
The event isn't sent the moment the call hangs up. Calls that weren't answered, and calls on a Finn with no analysis fields, are usually sent within about 5 minutes. Answered calls on a Finn with analysis fields are sent as soon as the analysis is saved, usually within about 5 minutes, and after about an hour at the latest with whatever analysis exists. webhooks has the details. Most integrations are built on this event. webhook-post-call has the full payload and handler code. Summary of the data fields:
| Field | Type | Notes |
|---|---|---|
call_uuid | UUID | The call. Use it with GET /api/v1/calls/{call_uuid}. |
finn_id | UUID or null | The Finn that handled the call. |
deployment_id | UUID or null | The deployment the call belongs to: the same id that GET /api/v1/deployments returns. null for calls that don't belong to a deployment, such as calls placed with POST /api/v1/calls. |
status | string or null | The call's final status. |
disconnect_reason | string or null | Why the call ended. |
direction | string or null | inbound or outbound. |
from_number, to_number | string or null | The two phone numbers on the call. to_number is in E.164 format. |
duration_seconds | integer or null | Call length in whole seconds. |
user_sentiment | string or null | Overall sentiment of the person called. |
call_successful | boolean or null | Whether the call met its goal, according to analysis. |
created_at, updated_at | ISO 8601 or null | When the call record was created and last updated. |
analysis | array | One entry per analysis field, newest first. Empty if no fields are set up. Can also be empty for a call that wasn't answered, or when analysis hadn't arrived after about an hour. |
status, disconnect_reason and user_sentiment can take new values at any time. Treat them as strings, not a fixed list.
Events that don't exist
Some integrations expect these events. Finn doesn't send them:
| Event | What to use instead |
|---|---|
call.started | Your 202 response from POST /api/v1/calls |
call.analyzed | call.completed waits for analysis on answered calls, so it already includes analysis |
call.transferred | Not available |
deployment.completed | Poll GET /api/v1/deployments/{id} |
wallet.low_balance | Poll GET /api/v1/wallet and read low_balance |
What breaks
| Symptom | Cause |
|---|---|
A handler expecting type or id at the top level throws | The fields are event and created_at. There's no top-level id. |
| A call never produces an event | All 3 delivery attempts failed, or the call ended before you added the endpoint. Older calls aren't backfilled. Check GET /api/v1/calls/{call_uuid}. |
analysis is empty | The Finn has no analysis fields set up, the call wasn't answered, or analysis hadn't arrived after about an hour. GET /api/v1/calls/{call_uuid} returns analysis that arrives later. |
Fields are null | The call record wasn't available when the payload was built. Read the call with GET /api/v1/calls/{call_uuid}. |
Related: webhooks, webhook-post-call, webhook-security, webhook-retries, api-webhooks.