Every call endpoint (create-phone-call, create-web-call, get-call, list-calls, stop-call, rerun-call-analysis) and every call webhook returns the same call object. Its shape is defined by CallResponse in packages/shared and matches Retell's field names, so code written against Retell reads it unchanged.
This page explains each field. For the list endpoint and its filters see List calls. For the reasons a call ends see Disconnection reasons.
Lifecycle#
A call moves through these states in call_status:
call_status |
Meaning |
|---|---|
registered |
The call exists but media has not started. Outbound calls are dialling; web calls wait for the browser to join; register-phone-call calls wait for your PBX to dial in. |
ongoing |
The agent is connected and the conversation is running. start_timestamp is set. |
ended |
The call finished after it started, or it ended before starting for a reason that is not a connection failure. |
not_connected |
The call never connected: busy, no answer, invalid number, declined, a web caller who never joined, and similar. |
error |
The call could not be placed at all (for example the room could not be prepared). disconnection_reason is dial_failed. |
ended, not_connected and error are terminal. A call becomes not_connected only when it never started and its disconnection reason is one of: dial_busy, dial_failed, dial_no_answer, invalid_destination, registered_call_timeout, error_user_not_joined, no_valid_payment, credit_exhausted, marked_as_spam, telephony_provider_permission_denied, telephony_provider_unavailable, sip_routing_error, concurrency_limit_reached, no_concurrency_fallback, user_declined.
When a call ends, Tried:
- Sets
end_timestamp,duration_ms,disconnection_reasonandcall_cost. - Sends the
call_endedwebhook. - Runs post-call analysis and stores
call_analysis. - Sends the
call_analyzedwebhook (always aftercall_ended). - Applies the agent's data storage setting.
Example#
{
"call_id": "call_7e2f4c1a9b8d0e3f5a6b7c8d",
"call_type": "phone_call",
"agent_id": "agent_3f9c0a1b2c3d4e5f6a7b8c9d",
"agent_version": 4,
"agent_name": "Receptionist",
"call_status": "ended",
"direction": "inbound",
"from_number": "+61412345678",
"to_number": "+61291234567",
"metadata": { "source": "google_ads" },
"retell_llm_dynamic_variables": { "business_name": "Harbour Dental" },
"collected_dynamic_variables": { "appointment_time": "Tue 21 Oct, 4pm" },
"start_timestamp": 1760850000000,
"end_timestamp": 1760850094000,
"duration_ms": 94000,
"transcript": "Agent: Hi, thanks for calling Harbour Dental...\nUser: I'd like to book a check-up.",
"transcript_object": [
{ "role": "agent", "content": "Hi, thanks for calling Harbour Dental...", "words": [] },
{ "role": "user", "content": "I'd like to book a check-up.", "words": [{ "word": "I'd", "start": 3.1, "end": 3.3 }] }
],
"transcript_with_tool_calls": [],
"recording_url": "https://...",
"recording_multi_channel_url": null,
"public_log_url": "https://api.tried.com.au/public/calls/call_7e2f.../log?exp=...&sig=...",
"knowledge_base_retrieved_contents_url": "https://api.tried.com.au/public/calls/call_7e2f.../kb-retrievals?exp=...&sig=...",
"disconnection_reason": "agent_hangup",
"call_analysis": {
"call_summary": "The caller booked a check-up for Tuesday at 4pm.",
"in_voicemail": false,
"user_sentiment": "Positive",
"call_successful": true,
"custom_analysis_data": { "appointment_booked": true }
},
"latency": {
"e2e": { "p50": 910, "p90": 1240, "p95": 1300, "p99": 1350, "max": 1360, "min": 780, "num": 9, "values": [910, 780] }
},
"call_cost": {
"product_costs": [
{ "product": "voice_infra", "unit_price": 0.08, "cost": 0.125333 },
{ "product": "gpt-5.6-terra", "unit_price": 0.1, "cost": 0.156667 },
{ "product": "voice_standard", "unit_price": 0.06, "cost": 0.094 }
],
"total_duration_seconds": 94,
"combined_cost": 0.376
},
"llm_token_usage": { "values": [1210, 1388, 1502], "average": 1367, "num_requests": 3 },
"batch_call_id": null,
"transfer_destination": null,
"contact_id": "contact_1a2b3c4d5e6f7a8b9c0d1e2f"
}Unit prices come from PRICE_PER_MIN in packages/shared/src/pricing.ts (for example voice_infra 0.08 AUD per minute).
Identity and routing#
| Field | Type | Description |
|---|---|---|
call_id |
string | Unique ID, prefix call_. |
call_type |
phone_call | web_call |
Phone calls go over SIP; web calls use WebRTC in a browser. |
agent_id |
string | The agent that handled the call. |
agent_version |
integer | The agent version used. Pinned at call creation. |
agent_name |
string, optional | Name of the agent's latest version. Returned by get-call and list-calls. |
direction |
inbound | outbound | null |
Null for web calls. |
from_number, to_number |
string | null | E.164 numbers for phone calls. |
batch_call_id |
string | null | Set when a batch campaign placed the call. |
contact_id |
string | null | The contact linked to this phone call. See Contacts. |
custom_sip_headers |
object, optional | Custom SIP headers passed to create-phone-call. |
stir_shaken_attestation |
A | B | C, optional |
Caller attestation when the carrier provides it. |
caller_cnam |
string, optional | Caller name when the carrier provides it. |
concurrency_burst |
boolean, optional | true when the call was placed over the base concurrency limit (a burst surcharge applies). |
transfer_destination |
string | null | Where the call was transferred, set when a transfer starts. |
Data you pass in#
| Field | Type | Description |
|---|---|---|
metadata |
object | Any JSON you set when creating the call. You can change it during the call with update-live-call and after it with update-call. |
retell_llm_dynamic_variables |
object of strings | Variables passed at creation. Contact fields are added to the agent's variables at runtime but are not written into this field. |
collected_dynamic_variables |
object of strings | Variables set during the call, for example by an extract variable tool or node. |
Timing#
| Field | Type | Description |
|---|---|---|
start_timestamp |
number | null | Epoch ms when the call connected. Null if it never connected. |
end_timestamp |
number | null | Epoch ms when the call ended. |
duration_ms |
number | null | end_timestamp - start_timestamp, or 0 for calls that never started. |
Transcript#
| Field | Type | Description |
|---|---|---|
transcript |
string | Plain text, one line per utterance, prefixed Agent: or User:. |
transcript_object |
array | Utterances { role, content, words }. words holds per-word start and end times in seconds when the speech-to-text provider returns them. |
transcript_with_tool_calls |
array | Utterances plus events, each with an optional ts. |
transcript_with_tool_calls item roles:
role |
Fields | Added when |
|---|---|---|
agent, user |
content, ts |
Someone speaks. |
tool_call_invocation |
tool_call_id, name, arguments (JSON string) |
The agent calls a tool. |
tool_call_result |
tool_call_id, content |
The tool returns. |
node_transition |
former_node_id, new_node_id, transition_type |
A conversation flow moves between nodes. transition_type is normal, global, global_go_back or interrupt_go_back. |
dtmf |
digit |
The caller presses a key. |
transfer |
event, destination, reason |
A transfer starts, bridges, is cancelled or ends. A dashboard take-over adds event: transfer_bridged with reason: take_over. |
agent_swap |
former_agent_id, new_agent_id |
The call moves to another agent. |
sms |
content, to_number |
The agent sends a text during the call. |
injected |
content |
You added context with update-live-call call_control.additional_context. |
ts is a millisecond offset from the call start or an absolute epoch ms value.
Recordings and logs#
| Field | Type | Description |
|---|---|---|
recording_url |
string | null | Mixed WAV recording. |
recording_multi_channel_url |
string | null | Dual channel recording (agent and caller on separate channels). |
public_log_url |
string | null | Signed link to the full runtime event log. |
knowledge_base_retrieved_contents_url |
string | null | Signed link to the JSON of every knowledge base retrieval in the call. |
Signed links for the log and retrievals last 7 days. If the agent enables signed recording URLs, recording links also expire, after signed_url_expiration_ms.
Needs keys Recordings need LiveKit egress and S3 credentials. In mock mode the call gets a placeholder WAV.
Outcome#
| Field | Type | Description |
|---|---|---|
call_status |
enum | See Lifecycle. |
disconnection_reason |
enum | null | Why the call ended. See Disconnection reasons. |
call_analysis |
object | null | Post-call analysis. Null until analysis finishes. |
call_analysis fields:
| Field | Type | Description |
|---|---|---|
call_summary |
string | A short summary of the call. |
in_voicemail |
boolean | Whether the call reached voicemail. |
user_sentiment |
Positive | Negative | Neutral | Unknown |
Caller sentiment. |
call_successful |
boolean | Whether the agent achieved the goal of the call. |
custom_analysis_data |
object | Your custom extraction fields by name. Fields that could not be determined are left out. |
See Post-call analysis and Use analysis results.
Latency#
latency is an object with one entry per stage that produced samples. Each entry has p50, p90, p95, p99, max, min, num (sample count) and values (every sample in ms, one per turn).
| Key | Stage |
|---|---|
e2e |
End of the user's speech to the agent's first audio. |
asr |
End of the user's speech to the final transcript. |
llm |
Time to the first LLM token. |
tts |
Time to the first audio byte from text to speech. |
knowledge_base |
Knowledge base retrieval time. |
llm_websocket_network_rtt |
Round trip to a custom LLM WebSocket. |
s2s |
Speech-to-speech engines: end of speech to first agent audio. |
Cost and usage#
call_cost:
| Field | Type | Description |
|---|---|---|
product_costs |
array | One line per product: product, unit_price (per minute), and cost. |
total_duration_seconds |
number | Billed seconds (rounded up). |
combined_cost |
number | Sum of product_costs[].cost in AUD. |
Products include voice_infra, the LLM model (for example gpt-5.6-terra), the voice (voice_premium or voice_standard), knowledge_base when the agent uses one, and concurrency_burst for burst calls. There is no telephony line: numbers are your own, and your carrier bills the phone line.
llm_token_usage is { values, average, num_requests }: total tokens per LLM request, their average and the request count. It is null when no LLM request was recorded.
Web call fields#
create-web-call responses also carry access_token, livekit_url, expires_at (token expiry, epoch ms), ice_servers and transport. register-phone-call responses carry sip_uri, the SIP URI your PBX dials.