Call event webhooks
An agent forwards
call.dialing, call.started, call.ended and call.recording to a URL you name.Webhook schedules
Call a URL, or run an automation, at times decided by rules: weekdays, windows, intervals, dates.
Webhook logs
The record of every request around a call: dispatch, room, config fetch and each report the voice engine sent.
agents.update to configure an agent’s webhook, schedules.read / schedules.create / schedules.update / schedules.delete for schedules, webhook_logs.read for logs. See Authentication for tokens and roles.
Call event webhooks
A voice agent can forward the events of every call it handles to a URL of yours. You choose which of the four event types leave the platform; the rest are processed by CallVA as always and go nowhere else.
Call event webhooks are produced for calls that run on CallVA’s own voice engine (the LiveKit worker), inbound and outbound.
How a call’s events travel
The voice worker reports each event to CallVA, signed with the project’s secret. CallVA verifies it, updates the call record (status, parties, timestamps, transcript, recording, billing), and only then forwards the report to your URL if the agent subscribes to that event type.Configure the receiving URL
The URL lives on the agent. Three fields control it, set with Update an agent (PATCH /agents/{id}) or in the dashboard on the agent’s settings:
boolean
Turns forwarding on or off.
string
Where the events are posted. Any valid URL up to 2048 characters.
string[]
The event types to forward: any of
call.dialing, call.started, call.ended, call.recording. The list you send replaces the stored one. An empty list forwards nothing, even with forwarding enabled and a URL set.Response (trimmed)
422:
Payloads
Each event is posted as a JSON object - the envelope the voice worker reported, with CallVA’s own credentials (signing secret, TURN password, LiveKit keys) removed and nothing else changed.string
required
call.dialing, call.started, call.ended or call.recording.string
required
Unique id of this report:
<call id>:<event>:<milliseconds>.number
required
When the report was built, Unix seconds with a fraction.
object
required
The call.
id is the CallVA call id - use it with Get a call.object
The agent configuration the call ran with, including any per-call override:
id, name, prompt, greeting and timeout settings, custom_webhook_enabled, custom_webhook_url.string | null
Which CallVA deployment served the call.
object
What the voice engine reported, verbatim:
room, job, participant, sip (SIP attributes such as callStatus) and disconnect_reason. On call.ended it also carries session_report, with chat_history.items (the raw conversation) and usage (per-provider usage). Not present on call.recording.object | null
On
call.ended, where the recording will be stored: delivery, audio_key, session_report_key. On call.recording, the same with stored: true. Keys are object names, never URLs; play the audio through Stream a call’s recording.array | null
What went wrong during the call, when anything did.
object | null
Session tags and outcome the agent recorded:
tags, outcome, reason.- call.dialing
- call.started
- call.ended
- call.recording
livekit.session_report.chat_history, with consecutive pieces of one speaker merged into utterances. If you want the stored version rather than the raw one, read it with Get a call’s transcript.
Delivery: headers, timeout, retries
The project’s webhook signing secret
Every project has a signing secret of its own (theagent_webhook_secret project setting). It authenticates the reports a voice worker sends to CallVA - the signed arrows in the diagram above - and only that project’s secret verifies that project’s calls. CallVA’s own worker receives the secret with each call’s configuration, so you need it only if you run your own LiveKit worker against CallVA, or relay reports to CallVA yourself.
The worker signs each report like this:
401 when a header is missing (missing_signature), the timestamp is more than 300 seconds from its clock (timestamp_expired), the signature does not start with sha256= (invalid_signature_format), the call is unknown (unknown_call), or the HMAC differs (invalid_signature). The same check, in code:
has_value and never contains the secret:
Response (trimmed)
project_secrets.read permission. Generating needs settings.update.
Webhook schedules
A webhook schedule calls one URL - or runs one automation - at the moments its rules allow. Use it for a nightly sync, a report every weekday morning, a heartbeat every five minutes inside office hours.The model
A schedule is the target and how to call it:webhook_url, webhook_method (GET, POST, PUT, PATCH, DELETE), webhook_headers, webhook_payload, timeout_seconds (1-300, default 30), max_retries (0-10, default 3), retry_delay_seconds (0-3600, default 60) and is_active. With target_type: "automation" and an automation_id, it runs that automation instead of calling a URL.
A rule says when. Each rule has a priority (lower runs first), an action (run or skip), and conditions that must all pass:
execution_interval (seconds, default 60, at least 10 for run rules, at most 86400) sets the cadence inside a matching window. Times are anchored to time_from (or midnight): an interval of 300 from 09:00 fires at 09:00, 09:05, 09:10 and so on, with time_to inclusive.
Rules are evaluated in priority order and the first rule whose conditions all pass wins. When no rule matches, nothing runs. A rule with is_exclusive: true and a date “owns” its dates: on those days no lower-priority rule is consulted, and outside its own time window the answer is skip. Use it for holidays and one-off days.
Rules are evaluated in the schedule’s timezone: the project’s timezone setting, else the organization’s, else UTC.
Pre-schedule, then execute
A scheduler ticks every ten seconds and does three things in order. An execution moves through these states:- One run per moment. A schedule and a run time identify an execution uniquely, so overlapping ticks cannot create or send the same run twice.
- No replay after an outage. If the scheduler was down and several runs of a schedule are due at once, only the newest is sent; the older ones are marked
skippedwithSkipped: newer execution available (heartbeat gap recovery). - Deactivating cancels planned runs. Executions already pre-scheduled re-check the schedule and rule when they come due and are marked
skippedif either was switched off (Schedule was deactivated before execution), without any request. max_retries: 0means one attempt. Connection errors, timeouts and non-2xx answers all count as failures.- What is sent.
POST,PUTandPATCHsendwebhook_payloadas JSON (withContent-Type: application/jsonunless your headers set one);GETandDELETEsend no body. Yourwebhook_headersare sent as given. Scheduled requests are not signed: put a credential for your endpoint inwebhook_headers. - Automation targets run the automation with no arguments, so every parameter of its
mainneeds a default.
Create a schedule
Create a webhook schedule:Response 201 (trimmed)
schedules.read only to roles that may see the credentials you put there.
Preview a moment
Preview a webhook schedule tells you which rule governs a moment and whether it runs. It checks the rule conditions, not interval alignment: a moment between two interval ticks still reportsrun if a run rule matches.
exclusive_block: true means an exclusive rule owns the date but the moment is outside its time window, so the answer is skip and no other rule was asked.
Read the execution history
List a schedule’s executions lists executions, upcoming (pre-scheduled) ones included. It is ordered bytriggered_at descending, so runs not yet triggered come first. per_page defaults to 50.
Response (trimmed)
success, failed, skipped) are deleted once older than the organization’s webhook_execution_retention_days setting: 30 days by default, between 7 and 90. An execution that stays in processing means the worker stopped mid-call; nothing reclaims it.
Update, pause and delete
Update a webhook schedule is a full replacement: send every field you want to keep. Omitted settings return to their defaults (max_retries 3, timeout_seconds 30, is_active true), and omitted rules are deleted. Send a rule’s id to keep and update it; a rule without an id is created.
Response (trimmed)
is_active: false pauses the schedule: no new runs are pre-scheduled, and runs already planned are marked skipped when they come due. Delete a schedule removes it with its rules and execution history:
per_page defaults to 15) and get one return schedules with their rules in priority order.
Webhook logs
Webhook logs are a project’s record of the HTTP exchanges around its calls, kept for debugging. Each entry stores the full request (method, URL, headers with credentials redacted, payload, source IP), the response (status, body, time taken), a processing status, an error message, and the call it relates to. Entries come from these exchanges:processing_status is success, validation_failed, processing_error or signature_invalid. Forwards to your custom webhook URL and scheduled webhook requests are not webhook-log entries; the latter have their own execution history.
List and filter
List webhook logs, newest first:Response (trimmed)
List webhook log filters returns the values to offer, including the event types that actually occur in this project:
One call’s logs
List a call’s webhook logs takes the same query parameters and answers404 when the call is not in the project:
One entry
Get a webhook log returns one entry with the same fields, plusrelated_call when it names a call:
Response (trimmed)
webhook_logs.read only to roles that should see that. Entries are deleted once older than the organization’s webhook_log_retention_days setting: 30 days by default, between 7 and 90.
Related
Automations
Point a call event webhook or a schedule at a script that runs inside CallVA.
Calls
The call record that events update and that webhook logs relate to.