A call trace is the after-the-fact story of one call: every stage it moved through, who handled each stretch, and how long each stretch took — all keyed by the one identifier that follows the call everywhere, the call_sid. Where webhooks give you the live stream of lifecycle events as they happen, a trace is the assembled view: those same events folded into a readable timeline you pull up when a call went wrong, a customer disputes what happened, or you’re auditing an AI→human handoff. This page is how to read that timeline — its segment model, how a transfer reshapes it — and how to pull it two ways: in the console call detail and over the control-plane API.

How a trace is assembled

Every transition a call makes on the wire is emitted as a lifecycle event — initiated at the INVITE, delivered when the far end is alerting, established on answer, held / retrieved on hold and resume, transferred on a REFER, and cleared on the final BYE (carrying the Q.850 cause and the billable duration). You don’t assemble anything yourself: the events pipeline collects those transitions for a call_sid and folds them into segment rows, computing the per-stage durations (ring, queue, talk, hold, wrap-up) as it goes. A trace is that ordered set of segments plus the roll-up totals.
The trace is derived from the signalling timeline — when the call rang, was answered, held, transferred, cleared. For the media side of the same call — MOS, jitter, packet loss — see MOS, jitter & loss; for where the latency went inside a turn, see latency breakdown.

Segments: one sid, one or many stretches

A simple call — one caller, one handler, start to finish — is a single segment. The interesting case is a call that changed hands. A transfer or handoff opens a new segment. The call_sid never changes (it’s one call, one CDR, one recording context), but the timeline splits at each hand-off so you can see exactly who owned which stretch and for how long. The canonical example is a warm AI→human handoff:
call_sid = cs_9f21…            (one call, two segments)

├─ segment 0   handler: AI agent "intake-bot"        (llm)
│    ring 2s → talk 34s → transferred ▶

└─ segment 1   handler: "Dana Okafor"                (human)
     queue 6s → ring 3s → talk 128s → wrap-up 20s → cleared (Q.850 16)
Each segment carries its own handler and its own stage timings; the trace’s totals sum them. That’s why a transferred call reads as one continuous call in reports rather than two disconnected records.
What opens a new segment. A change of handler — a transferred (REFER) transfer, or a warm AI→human handoff. Holds, resumes (held / retrieved), and mid-call media renegotiation (reinvited) do not open a new segment — they’re recorded within the current segment as hold time and flags. A handler is tagged llm (an AI agent owned the stretch) or human, so you can split talk time by who was actually on the line.

What each segment tells you

Field on a segmentWhat it means
handlerKind / handlerDisplayNameWho owned this stretch — an AI agent (llm) or a named human (human).
ringTimeSecTime the leg spent alerting before it was answered.
queueTimeSecTime waiting in an ACD skill queue before a handler picked up (human segments).
talkTimeSecTwo-way audio time — the part of the call that was actually a conversation.
holdTimeSecTime this segment spent on hold (summed across every hold).
acwTimeSecAfter-call work / wrap-up time a human agent spent after the caller left.
durationSecWall-clock length of the segment.
transferred / held / conferenceFlags: did this stretch end in a transfer, get held, or fan out to a supervisor.
disposition / hangupReasonThe wrap-up code applied and the Q.850 clearing cause.
recordingUrlLink to the segment’s recording, when recording is enabled.

Pull a trace in the console

The console call detail is the fastest way to read one call.
1

Open the calls report

In the voice console at agent.telequick.dev, go to Reports → All Calls. Filter to the window and the number, agent, or direction you’re chasing.
2

Open the call

Click the call to open Call Detail. The header shows the call_sid, direction, caller/callee, and the roll-up totals (total talk, hold, and duration; whether it was transferred).
3

Read the segment timeline

The body renders the segments oldest-first, top to bottom. Each row names its handler (AI or human), its stage timings, and its disposition. A multi-segment call shows the transfer hop inline — AI segment, then the human segment it handed to.
4

Play the recording

Where recording is on, each segment links its own recording (caller on the left channel, handler on the right) so you can listen to exactly the stretch you’re auditing.
In-flight calls. A call that’s still on the wire hasn’t been folded into segments yet. Call detail still renders a live view for it — direction, tenant, the bound agent, and when it started — so an active call isn’t a blank page. The full segment timeline appears once the call clears.

Pull a trace over the API

The same assembled trace is a control-plane read, keyed by call_sid and scoped to your workspace by your API key. Use it to feed a QA tool, a dispute workflow, or your own reporting — anything that needs the structured timeline rather than the raw event firehose.
This is a control-plane reporting read, distinct from calls.get, which returns a point-in-time Call snapshot (current status), not the historical timeline. Fetch the trace from the control-plane API host with your API key; the response is the same data the console renders.
// Assembled per-segment timeline for one call, keyed by call_sid.
const res = await fetch(
  `https://engine.telequick.dev/reports/calls/${callSid}`,
  { headers: { authorization: `Bearer ${process.env.TELEQUICK_API_KEY}` } },
);
const trace = await res.json();

for (const seg of trace.segments) {
  console.log(
    `#${seg.segment}`,
    seg.handlerKind,                       // "llm" | "human"
    seg.handlerDisplayName,
    `talk=${seg.talkTimeSec}s hold=${seg.holdTimeSec}s`,
    seg.transferred ? "→ transferred" : "",
  );
}
console.log("total talk:", trace.totals.talkTimeSec);
import os, requests

res = requests.get(
    f"https://engine.telequick.dev/reports/calls/{call_sid}",
    headers={"authorization": f"Bearer {os.environ['TELEQUICK_API_KEY']}"},
)
trace = res.json()

for seg in trace["segments"]:
    print(seg["segment"], seg["handlerKind"], seg["handlerDisplayName"],
          f"talk={seg['talkTimeSec']}s hold={seg['holdTimeSec']}s",
          "→ transferred" if seg["transferred"] else "")
print("total talk:", trace["totals"]["talkTimeSec"])

Response shape

callId
string
The call_sid this trace belongs to.
segments
array
The ordered segments, oldest first. Each carries segment (index), startedAt / endedAt, handlerId / handlerKind (llm | human) / handlerDisplayName, the stage timings (ringTimeSec, queueTimeSec, talkTimeSec, holdTimeSec, acwTimeSec, durationSec), the flags (transferred, held, conference), disposition, hangupReason, and recordingUrl.
totals
object
Roll-up across all segments: segments (count), talkTimeSec, holdTimeSec, ringTimeSec, queueTimeSec, durationSec, and whether the call was transferred or conferenced anywhere.
live
object | null
Present only while the call is still on the wire — direction, bound agent, and start time for an in-flight call whose segments haven’t been assembled yet. null once the call has cleared and segments exist.

When a trace looks wrong

SymptomLikely causeWhat to check
Trace is empty / live is nullThe call_sid never landed, or belongs to another workspaceConfirm the sid from the calls list; a trace is tenant-scoped — a sid from another workspace returns not-found.
Call shows one segment but you expected a transferThe transfer was a held/reinvited (same handler), not a handler changeOnly a handler change (transferred / handoff) splits segments; holds stay in-segment.
Segments exist but timings are zeroThe call is still assembling, or never reached two-way mediaAn in-flight call surfaces as live first; a call that failed before answer has no talk time.
Peer transfer acknowledged but the onward leg is missingExecuting an outbound leg from a peer-initiated REFER is only partially wiredPrefer operator-initiated transfers; the peer-REFER onward leg may not complete.
Recording link missing on a segmentRecording wasn’t enabled for that leg, or hasn’t finished uploadingConfirm recording is on for the trunk/agent; recordings land shortly after cleared.

Call lifecycle

The signalling state machine every event in a trace comes from.

Webhooks & events

The live event stream a trace is assembled from.

Handoffs

How a transfer or warm AI→human handoff opens a new segment.

MOS, jitter & loss

The media-quality side of the same call.

Dashboards

Fleet-wide views built from the same call data.

Calls API

Originate, get, transfer, and hang up — the live control plane.