Skip to content

Event catalogue

An event is a fact that happened, such as “a call was answered”. Each service writes its events in the same step as the change itself, so an event is never published for something that did not happen. There are 35 subjects. The list is also served live by GET /api/integrations/v1/events/catalog, with an example for each.

Every event is wrapped the same way:

{ "id": "…", "tenant_id": "…", "at": "2026-10-06T14:03:11Z", "source": "call-control",
"subject": "vd.call.answered", "data": { … } }

id is unique and stable, so a receiver can ignore repeats. source is the service that emitted it.

A webhook connector chooses subjects with wildcards (for example vd.call.*) and optionally one campaign. Every subject below can be chosen. Deliveries are signed, retried and listed under webhooks. Phone numbers in the payload become the last four digits unless the connector asks for full numbers.

The live screens use a second kind of message, called a live topic, such as campaign.runtime, campaign.warning and agent.state. Those are only for the web app and are not delivered to webhooks.

Subject When Main fields
placed A call was started call_id, direction, from_number, to_number, campaign_id, lead_id, attempt_id, journey_id, trunk_id
ringing It is ringing call_id, journey_id, campaign_id
answered Someone or something answered call_id, amd_result (human, machine, unknown), handled_by (bot, agent, bot_overflow, none), ring_ms
failed It never connected call_id, reason (no_answer, busy, rejected, carrier_error, node_failure, cancelled), sip_code
ended An answered call finished call_id, end_reason (lead_hangup, bot_ended, agent_hangup, transfer_external, node_failure, abandoned, machine, system), talk_ms, answered
leg_joined, leg_left A participant joined or left call_id, leg_id, kind (lead, bot, agent, supervisor, external), participant, mode
recording_stored A recording was saved call_id, recording_id, duration_ms, sha256
Subject When Main fields
opened, closed A person’s journey starts or ends journey_id, lead_id, campaign_id; on close status, final_disposition
stage_started, stage_completed A step began or ended stage_run_id, kind, handler, status
fact_recorded An answer was noted key, value, plausible, source
consent_recorded Consent was captured on a call consent_id, kind, status
disposition_set A result was saved code, category, is_final, call_id
transfer_requested, transfer_bridged, transfer_failed, transfer_completed A hand-over moved on transfer_id, to_kind, handler, status, billable_seconds, billable, failure_reason
callback_scheduled A callback was booked callback_id, due_at, reason
outcome_updated A sale or revenue was reported enrolled, revenue_cents
Subject When Main fields
session_started A bot conversation began session_id, call_id, bot_version_id, role
transcript_line A line was spoken call_id, idx, role (caller, bot, agent, system), text
reply_timing The bot replied turn, ms
session_ended It ended end_reason, seconds, cost_usd, turns, reply_ms_p50, reply_ms_p95

Transcript text is not scanned for phone numbers.

Subject When Main fields
vd.dialer.attempt_denied A dial was refused attempt_id, campaign_id, lead_id, reason_code (see dial-check reasons)
vd.dialer.campaign_state_changed A campaign ran, paused, drained or stopped campaign_id, state, reason
vd.compliance.dnc_added A number was added to the do-not-call list phone_hash_hex, scope, source
vd.compliance.complaint_logged A complaint was logged complaint_id, journey_id
vd.qa.scored The QA Bot scored a call review_id, score, passed, flags, needs_review
vd.list.verified A list check finished list_id, total, ready, rejected
vd.agent.state_changed An agent changed state user_id, state, pause_code, campaign_id

Bulk do-not-call imports write one audit line, not one event per number.

Subject When Main fields
tenant_limits_changed An operator changed a plan limits, changed_by
ai_minutes_threshold AI minutes reached 80% or 100% of the month’s cap month, used_minutes, cap_minutes, percent
dialing_pause_changed The kill switch was set or lifted scope (global or tenant), paused, reason, by

A global pause belongs to no company, so no company’s webhook should receive it.