Get started
Call flow
Every call in Voxa moves through a small set of statuses, and this page explains each one: how a call starts, what happens while it runs, how it ends, and what Voxa keeps afterwards.
Statuses
| Status | Meaning | Final |
|---|---|---|
queued | An outbound call is waiting for a free call slot, credits or the agent’s calling hours. | No |
ringing | Voxa has asked Plivo to dial the number. The call holds a call slot. | No |
in-progress | The caller answered (or called in) and the agent is live. | No |
completed | The conversation ran and ended normally, whoever hung up. | Yes |
failed | Something went wrong: no credit, the phone provider refused the call, a speech service failed, or the server restarted mid-call. | Yes |
no-answer | The number rang but nobody picked up. | Yes |
busy | The number was busy. | Yes |
canceled | The call was canceled while queued, expired in the queue, its agent was deleted, or Plivo reported it canceled before it connected. | Yes |
outbound: queued ──> ringing ──> in-progress ──> completed
│ │ └───────> failed
│ ├──> no-answer / busy / failed / canceled
├──> canceled (canceled, expired, agent deleted)
└──> failed (out of credits, phone provider refused)
inbound and browser: in-progress ──> completed / failed
hangup_by and hangup_reason on the call say why it ended. See The call object.
Three ways a call starts
| Outbound | Inbound | Browser | |
|---|---|---|---|
| Started by | POST /api/v1/agents/{id}/call | Someone dials a number connected to an agent | The console’s Test in browser, or a WebSocket client |
direction | outbound | inbound | web |
channel | phone | phone | web |
| First status | queued | in-progress | in-progress |
| Waits in the queue | Yes | No; refused if no slot is free | No; refused if no slot is free |
| Calling hours apply | Yes, unless ignore_call_window | No | No |
user_data | From the request | Empty | From the first WebSocket message |
| Audio | 8 kHz mu-law over Plivo | 8 kHz mu-law over Plivo | 16 kHz 16-bit PCM over a WebSocket |
Read more: Outbound calls, Inbound calls, Browser calls.
The queue
Every outbound call is queued, even when a slot is free. A background worker dials queued calls, oldest first, for each workspace. It runs as soon as a call is queued or a call ends, and also every few seconds as a safety net.
For each queued call, the worker checks, in order:
- Age. A call queued longer than 24 hours is
canceledwith the reasonexpired in queue. - Free slot. If the workspace’s live calls (
ringingplusin-progress) already reach its concurrency limit, the call waits. It also waits while the workspace is not active. - Credits. If the balance is ₹0 or less, the call is
failedwithout of credits. - Agent. If the agent was deleted, the call is
canceled. - Calling hours. If the current hour in the agent’s time zone is outside its calling window, the call waits until the window opens.
Then the call moves to ringing (taking the slot before dialling) and Voxa asks Plivo to dial. If Plivo refuses, the call is failed and the slot goes to the next call.
Queued calls survive a server restart. They are stored, and the worker dials them when it comes back.
Limits and billing covers concurrency limits and how to ask for more.
Calling hours
Each agent has a calling window: call.call_start_hour (default 9) to call.call_end_hour (default 21), in call.timezone (default Asia/Kolkata). An outbound call is dialled only when the current hour h satisfies call_start_hour <= h < call_end_hour. With the defaults, the last calls go out at 20:59.
- Calls queued outside the window wait in the queue. The
call.queuedevent says so:queued at position 1; waits for the calling window (9:00-21:00). - Pass
"ignore_call_window": truewhen placing a call to skip the check. - The window does not wrap past midnight. If
call_start_houris not less thancall_end_hour, the window never opens. - A call still waiting after 24 hours expires.
While the call runs
Once a call is in-progress, the agent’s session runs:
- Welcome. If the agent has a
welcome_message, it is spoken first, with{variables}filled in. - Listen. The transcriber turns the caller’s audio into text and decides when the caller has finished a turn.
- Think. The LLM gets the conversation and the agent’s prompt and streams a reply. It can call the agent’s tools, or the built-in
end_call. - Speak. Each sentence goes to the voice as soon as it is complete, so the agent starts talking before the full reply is ready.
- Interruptions. If the caller talks over the agent (at least
interruption_min_wordswords), the agent stops, drops the audio not yet played, and answers what the caller just said. - Watchdog. Every second, Voxa checks the maximum length, silence, the “are you still there?” check and the credit limit. See the Call tab.
Each step is written to the call’s timeline (GET /api/v1/calls/{id}/events) and sent to your webhooks.
How a call ends
| Who | hangup_by | Typical hangup_reason |
|---|---|---|
| The caller hangs up | caller | caller hung up |
The agent calls end_call | agent | agent ended the call |
| The hang-up prompt says the conversation is over | agent | hang-up prompt: conversation complete |
Nobody speaks for hangup_after_silence_seconds | agent | caller was silent |
The call reaches max_duration_seconds | agent | maximum call length reached |
| The workspace runs out of credit mid-call | agent | credits ran out |
You end it with POST /api/v1/calls/{id}/hangup | api | ended from the console |
| A speech service fails | error | speech services unavailable: ... |
| Voxa ends it before or outside the session | system | expired in queue, out of credits, server restarted during the call |
After the call
When the session ends, Voxa, in this order:
- hangs up and closes the speech services;
- computes usage (seconds of audio transcribed, characters spoken, LLM tokens);
- charges the call per second from your credits;
- saves the recording, if
call.recordis on; - saves the final status and emits
call.ended; - runs post-call analytics (summary and extraction), if turned on;
- sends
call.completedwith the full call record to your webhooks.
call.completedis sent only for calls that connected and ran a session. Calls that end asno-answer,busy,canceled, or fail before connecting, getcall.endedbut nocall.completed.
What Voxa records
| What | Where | Kept |
|---|---|---|
| Call record: status, numbers, timing, usage, cost, summary | GET /api/v1/calls/{id} | With the call |
| Transcript: every caller and agent turn, interrupted replies marked, tool calls | transcript on the call | With the call |
| Timeline: every event with its latency | GET /api/v1/calls/{id}/events | A set number of days (platform setting) |
| Recording: stereo WAV, caller on the left, agent on the right | GET /api/v1/calls/{id}/recording | On the Voxa server |
| Credit charge | Billing ledger, with the call id | With the workspace |