Skip to main content
Call events track a call through its whole life. Every event for one call carries the same call_uuid, so you can join them into a single timeline: call.started → call.ringing → call.answered → call.held / call.resumed → call.ended → call.recording_ready Two more events sit outside that sequence. call.completed sends a call’s post-call data (call details, recording, transcript, Conversation Intelligence, AI Voice Agent and Dialer results) as one event after the call. call.tags_modified fires whenever tags are added to or removed from a call, during the call or long after it ended. These are account-level webhooks, delivered to the endpoints you register under Settings → Webhooks. See the overview. All examples on this page show the full request body, including the envelope. Fields with empty values are omitted from payloads rather than sent as null. There are three exceptions: tags[].name on call.tags_modified; the intelligence section of call.completed, whose fields can be null where cidata.ready documents them as nullable; and values nested inside voice_agent.extracted_data on call.completed, which can be null, for example when a value was too deeply nested to keep (see Size limits and truncated under call.completed). voice_agent.extracted_data itself is always an object. Accept null in those places. Fields shown in bold are always present. A bold field nested inside an optional object is always present whenever that object is. Everything else is optional.

Common objects

Two objects appear across call events.

The contact object

Each entry in contacts is a contact from your account that matches the call. Every field except id is included only when it has a value.

The user object

The user field identifies the CloudTalk user handling the call. It is omitted (never null) when no user is assigned yet. Every field except id is included only when it has a value. The same object appears wherever a user is referenced on other events: favorite_user on contacts, user on messages, and callers[].user on Conversation Intelligence events.

Number types

Every number object (internal_number on call and message events, default_outbound_number.number and associated_numbers[] on user events) carries a number_type with one of these values: New values may be added over time; handle unknown values gracefully rather than failing.

Large contact sets

A call can match many contacts, and a number shared by many contacts does so routinely. To keep every payload deliverable, the first 10 matching contacts are included in full; any beyond that are included as { "id": "44211" } only, carrying the id and nothing else, and the event carries "contacts_truncated": true. Fetch the details of the id-only entries from the Contacts API when you need them. Every event that carries contacts also carries contacts_total, the number of contacts that matched before any trimming. Compare it with the length of contacts:
  • Equal: every matched contact is present, some as id only. You are missing detail, not contacts.
  • Greater: the matched set was so large that trailing ids had to be dropped to keep the event deliverable. You are missing contacts entirely and cannot tell which; fetch the call’s contacts from the API instead.
One more case sets contacts_truncated at any list size: a single very large contact record (many custom fields, phone numbers or emails) is reduced to { "id" } when the set would otherwise exceed its size budget. When nothing was trimmed, contacts_truncated is absent. This applies to every call event that carries contacts: call.started, call.ringing, call.answered, call.ended, and call.recording_ready. call.completed keeps at most 2 contacts; see its call.contacts field.

call.started

Fires the moment a call begins: as soon as an inbound call reaches your account or an outbound call is placed, before anyone picks up. Use it to pop the caller’s record in your CRM, start tracking a live call on a wallboard, or kick off any workflow that needs to know a conversation is underway.
Example

call.ringing

Fires when a call starts ringing on a specific user’s phone or app. Use it to alert the right person in your own tools, show who is being called on a live dashboard, or prepare a screen pop before the user picks up. The payload has the same shape as call.started; user identifies the user being rung.
Example
A call that rings several users in sequence or in parallel can produce more than one call.ringing event. Each identifies the user being rung.

call.answered

Fires when a call is picked up and the conversation begins. Use it to log pickup times, start measuring talk time, or update a live view of ongoing conversations. The payload has the same shape as call.started; user identifies the user who answered.
Example

call.held

Fires when a call is placed on hold. Use it to measure hold time, keep live dashboards accurate, or trigger reminders when a hold runs long. Hold events carry the call reference and, when the hold is attributable to one, the user. Join on call_uuid with the other lifecycle events for contact and number context.
Example

call.resumed

Fires when a call is taken off hold. Pair it with call.held to calculate hold durations, or use it to keep live call status accurate. The payload has the same shape as call.held.
Example
When computing hold durations, tolerate unpaired events: a call.resumed can arrive without a preceding call.held, and delivery order is not guaranteed. Pair on call_uuid and order by occurred_at.

call.ended

Fires when a call finishes and its final details have been processed: direction, the numbers involved, start time, durations, whether the call was recorded, and whether it went to voicemail, together with the matched contacts and the user who handled it. Use it to log completed calls in your CRM or helpdesk, trigger post-call follow-ups, or feed reporting the moment a call wraps up.
If the call was recorded, the recording is announced separately (sometimes minutes later) by call.recording_ready. Don’t expect recording details on call.ended.
Example

call.recording_ready

Fires when a call’s recording (including voicemail messages) has been stored and is available. This is an asynchronous event: it fires after call.ended, sometimes minutes later. Use it to kick off post-call workflows such as QA review, coaching, or attaching the recording reference to your CRM record of the call. It fires for every recorded call. The only prerequisite is that call recording is switched on for that direction in your account settings; transcription and Conversation Intelligence are not required.
The event does not include a download link. Use call_id with the Recording media endpoint to retrieve the recording with your API credentials.
Example
Voicemail recordings arrive as regular call.recording_ready events. To tell whether a recording is a voicemail, check is_voicemail on the matching call.ended event (same call_id).

call.completed

Fires once per call after it ends, with the call’s post-call data in one event: the call details from call.ended, the recording, the transcript reference, the Conversation Intelligence results, the data an AI Voice Agent extracted, and the Dialer disposition and survey. Use it when you want one webhook per call rather than joining up to seven events on call_uuid yourself. Each part of the payload is a section: call, recording, transcript, intelligence, voice_agent and dialer. You don’t need to subscribe to the individual events to receive call.completed. Endpoints subscribed to them still receive them, unchanged. When it fires call.completed is sent once per call, at whichever of these comes first:
  • every section the call is expected to have has arrived: completed_reason is all_ready. This is never earlier than about 2 minutes after the call ended;
  • 30 minutes have passed since the call ended (ended_at on its call.ended): completed_reason is deadline.
When a call ends, CloudTalk works out which sections the call can have, and marks the others not_applicable instead of waiting for them (see Expected sections below). Most calls are therefore sent a few minutes after they end, once the recording and the Conversation Intelligence results have arrived. It can still take up to 30 minutes. That happens when a section CloudTalk expected never arrives, for example when an agent had a Dialer session open but saved no disposition, or on an unanswered outbound attempt. It also happens when CloudTalk could not tell whether a section applies: it then waits for it.
  • No re-send. Data that arrives after call.completed was sent is not added, and call.completed is not sent again. The late data’s own event, for example cidata.ready, is still sent to endpoints subscribed to it.
  • No ordering. call.completed can reach your endpoint before or after the individual events for the same call.
  • One event_id per call. Every delivery of a call’s call.completed carries the same event_id and the same body. occurred_at is when the event was assembled, not when the call ended; the call’s end is data.call.ended_at.
  • Calls that ended before you subscribed. A call that ended before your endpoint was subscribed to call.completed never produces one.
Sources sources gives the status of each of the six sections. A section whose status is not ready is left out of data, so check sources before reading a section. New section names may be added to sources within v1; ignore names you don’t recognize. Expected sections When the call ends, each section is either expected or not_applicable: When CloudTalk is missing the information to decide, the section stays expected and is waited for. A section that arrives before call.completed is sent is included and reported ready, even if it was marked not_applicable. One that arrives after is not added; its own event is still sent. Size limits and truncated A call.completed request body is at most 64 KB (65,536 bytes). To fit, each section carries only the fields listed under Fields below, within these limits: Any other long text in a section can also be shortened so the section fits. Identifiers, timestamps and URLs are never shortened. A section is failed when one of its identifiers, timestamps or URLs is too long, or when it is still too large once nothing else can be shortened. If the whole body is still over 64 KB, whole sections are left out, largest first and call last, and reported failed. Everything shortened or left out is listed in truncated as a path that starts with the section name, for example call.contacts or intelligence.summary.summary. A shortened text ends with the marker …[truncated]. Fields the individual event had already shortened (its own truncated) are listed too. truncated holds at most 20 paths and 1,024 bytes; beyond that, paths are shortened to their first two parts (voice_agent.extracted_data), then to the section name (voice_agent). truncated is absent when nothing was shortened. Example A recorded inbound call with Conversation Intelligence, which no AI Voice Agent handled, answered by an agent with no Dialer session open. It was sent once the transcript and Conversation Intelligence results arrived, about four minutes after the call ended. Three contacts matched; two are included.
Example
Fields Fields copied from an individual event have the meaning that event’s reference gives them.
call.completed v1 has no recording_url and no insights_url. Get the recording from the Recording media endpoint and the AI results from the Conversation Intelligence API, both by call_id.

call.tags_modified

Fires when tags are added to or removed from a call: by a user during or after the call, or by an automation. Use it to mirror call tagging into your CRM or ticketing system, trigger follow-ups when a specific tag is applied, or drive reporting on how calls are categorised. Each event describes one change: the direction (added or removed) and the tags involved. It is a delta, not the call’s full tag list; to know a call’s current tags, fetch the call from the API rather than reconstructing them from a sequence of events.
Example
Unlike the other call events, call.tags_modified carries no contacts or user. For that context, join on call_uuid with the call.started or call.ended event you stored, or fetch the call from the API.