Calls and the voice agent
How ZeroReach places AI calls, what the voice agent does on a call, and the checks that run before every dial.
How a call starts
ZeroReach places AI calls in three situations, and never from an ad-hoc "dial" request:
| Trigger | What happens |
|---|---|
| A sequence call step | The runner queues the call; a background job dials it. |
| Speed-to-lead | A lead arriving on the inbound lead webhook is called right away, if the workspace turned speed-to-lead on. |
| A callback the lead asked for | The lead's "call me tomorrow at 3pm" becomes a call at that time, read in the lead's time zone. |
Each path follows the same pattern:
- Re-check at run time. Consent may have been revoked, an opt-out recorded, or the window closed since the call was queued. The checks are listed below.
- Record before dialling. The call is stored with its
call_startedevent (which the frequency caps count) before the phone rings, so a retried job never dials twice. - Dial once.
A permanent denial (no consent, suppressed, no phone) ends the call as failed without dialling, and turns it into a task for a person, with the reason. A temporary denial (outside the calling window, a cap) retries at next_allowed_at.
With no telephony configured, nothing dials: the server fails closed (telephony_not_configured).
The Caller agent
agent_paused); campaign calls and callbacks become tasks instead. With the Caller at suggest, speed-to-lead calls are skipped (agent_suggest_only).Checks before every dial
Every outbound call passes the same compliance gate (can_contact for the phone channel), in code:
- A phone number is present.
- No suppression matches the number, email, LinkedIn URL or domain.
- No revoked consent.
- A consent basis exists. For an AI voice, ZeroReach requires prior express written consent for every line type, landlines included, because an AI voice is an "artificial voice" under the TCPA. Web forms can record that consent with the lead.
- The calling window is open in the recipient's local time, and today is not a holiday under the country's policy.
- The frequency caps per lead and per number are not reached.
- Contact pressure across all channels allows another touch.
Sending limits then apply: calls per caller ID per hour and per day (30 and 150 by default), per workspace per minute (10) and per provider per minute (60). See Compliance for the details.
On the call
The voice agent is a phone agent built on LiveKit Agents (speech-to-text → LLM → text-to-speech).
- Disclosure first. The agent opens with a greeting that says it is an AI assistant and that the call is recorded. The greeting comes from code, is spoken before the LLM says anything, and can't be interrupted. A prompt without the disclosure fails to load.
- Stages. The call moves through intro → qualifying → scheduling → closing. In each stage the agent has only that stage's tools: confirm identity, save qualification answers (BANT by default, or the workspace's own fields), search approved knowledge-base answers, check availability and book one of up to three offered slots, schedule a callback, ask for a human, or opt out.
- Meetings are offered inside the workspace's business hours (Monday to Friday, 09:00–17:00 and 30-minute meetings by default).
- Opt-out in code. If the caller says "stop calling", "remove me" or similar, the opt-out is recorded for phone and email even if the LLM misses it. The agent then only closes the call.
- The outcome is decided by code, not by the LLM:
booked,callback_scheduled,not_qualified,opted_out,human_requested,wrong_person,no_decisionorcaller_hung_up.opted_outoverrides any other outcome. - Voicemail. The default is to hang up on an answering machine. Admins can choose to leave a short, pre-approved message (
PUT /api/v1/workspaces/current/voicemail) where the callee's country allows it.
The voice agent reports back through /api/v1/calls/{call_id}/... routes with a per-call token. Writes to a call that already ended answer 409 call_closed; opt-outs are never refused.
After the call
- The transcript is stored, and a background job asks the AI for a summary and the extracted fields.
- Empty lead fields (name, title, email) are filled from the caller's own corrections, and a lead without a company is linked to the one they named.
- If the outcome warrants it and the lead may be emailed, a recap email is drafted as a
call_recapreply draft. It waits for a person's approval. - The Meeting copilot turns the analysis into internal updates (when it is on and set to
auto, the default): the lead's open deal gets the agreed next step and a call-summary note, and each follow-up we promised becomes a task. Atask_firstorsuggestthese are only listed. Nothing here reaches the lead.
List calls with GET /api/v1/calls and a lead's calls with GET /api/v1/leads/{lead_id}/calls. Status is queued, ringing, in_progress, completed, failed, no_answer, voicemail or busy.
Test calls
Admins can talk to the live voice agent from the browser (Settings → Voice → Test call; POST /api/v1/voice/test-calls). Nothing is dialled: the call runs over WebRTC, which is the only reason it skips the telephony checks.