Execution Logs
Every turn of a finished call — what the agent heard, how long it thought, when the caller heard a reply — plus the webhooks it sent, the prompt it ran on, and the raw numbers behind all of it.
A call that went wrong is rarely wrong everywhere. It is one turn where the transcriber took two and a half seconds to settle, or one where the model thought for 1.8 s, or one where the reply never reached the caller at all. The execution log is that call broken into turns, so the question stops being "why was this call slow?" and becomes "which turn, and which stage of it".
Every finished call has one. Phone calls and web calls produce the same log from the same measurements.
Where to find it
| Route | Use it when |
|---|---|
/history → open a call → Open full logs | You started from the call |
/history/{execution_id} | You have the execution id |
/agent-executions/{agent_id}/{execution_id}/logs | You are debugging one agent and want a URL that names it |
All three render the same view. The agent-scoped URL exists because it can be pasted into a ticket and read by a colleague who then knows which agent it is without opening it.
Turn timing
One row per turn, three stages per row.
| Column | What it measures |
|---|---|
| Heard | From the caller starting to speak to the transcriber settling on the final text |
| Thought | From the text being handed to the model to its first token |
| Spoke | From the model's first token to the first audio the caller actually hears |
| Reply took | The three added together — what the person on the phone waited through |
A dash is not a zero. It means that stage produced no measurement for that
turn, and the row says which one — "no listening timing", "no speaking timing".
A turn with no spoke timing is a synthesizer that never reported, which is a
different investigation from an ASR that never finalised. Reply took is
blank whenever any stage is missing: a partial sum reported as a whole would be
smaller than the truth, and that is the one direction a latency figure must
never be wrong in.
The first row is often Greeting rather than a number. The synthesizer
numbers the welcome message -1 because it precedes the conversation; it has a
speaking time and no listening or thinking time, because nobody had said
anything yet.
A reply spoken as several sentences is still one turn. Spoke is the first sentence — the moment sound arrives — and the turn's total speaking time is the sum of them.
The log
Everything that happened, in the order it happened, with a wall clock against each entry and three facts about which part of the platform produced it:
A ~ before a timestamp means it was derived, not recorded. Only the
transcriber writes a wall clock; the model and the synthesizer record durations.
The rest of the turn is reconstructed from that anchor plus what each stage
took. Shown identically to a recorded time, someone would correlate it against a
carrier log and reach the wrong conclusion — so it is marked.
Entries expand where there is more to see:
- What it heard on the way — the drafts the transcriber produced before settling. This is the evidence for a misheard turn, and every view that shows only the final transcript throws it away.
- Conversation the model had in front of it — the transcript as it stood when that turn was decided.
The log is reconstructed, not replayed. Nothing writes a row when the model is called. Logging every request in full would mean writing the entire system prompt to the database on every turn — the same tens of kilobytes repeated per exchange, carrying whatever that prompt says about the person being called. The timings, the transcripts and the discarded drafts answer "why was this slow?" and "what did it mishear?" without keeping a copy of the prompt beside every customer's phone number.
Webhooks
Every webhook the call sent and whether it landed — event type, endpoint, attempt count, result, and the failure reason where there is one. A customer whose CRM never received a call asks exactly one question, and this is the answer to it.
An empty tab means no endpoint was subscribed, not that delivery failed. Subscriptions live in Integrations.
Instructions
The system prompt this call ran on, with a badge saying which one you are looking at:
- exactly what was sent — the prompt was snapshotted when the call ended.
- the agent's current prompt — it may have changed since — no snapshot exists for this call, so the agent was read as it stands now. An agent edited since the call would otherwise present a prompt that was never sent, and look authoritative doing it.
Raw data
The numbers exactly as each service recorded them, before any of the above is computed from them. When a reading looks wrong, this is the next step, and getting to it should not require a support ticket.
Downloading
- Download logs — a
.logfile: the header, the full event stream, the webhook table and the prompt, as text a person can paste into a thread. - JSON — everything the API returned, including fields the page does not draw.
Both are named execution-{execution_id} because that is what a ticket is filed
under.
The API
Separate from GET /api/v1/calls/{execution_id} because it is large — the
prompt alone is tens of kilobytes — and nothing wants it until someone opens a
call and asks why it went the way it did.
When there is nothing to show
measured is false and not_measured_reason says why. The three cases mean
genuinely different things and should not be reported to a user as one:
not_measured_reason | Meaning |
|---|---|
in_progress | The call has not finished writing. Detail appears when it ends. |
never_recorded | The call predates this telemetry. A gap in history — nobody should go looking. |
no_turns_completed | The call connected and no turn completed. Nobody spoke before it ended, which is a real finding about the call. |
Where the numbers come from
The engine measures each turn as it runs and reports the timings when the call ends. Web calls report straight through; phone calls carry the same measurements through the telephony gateway, which folds every report it receives so a later, thinner one can add to the record and never take anything out of it.
The three services keep separate books and do not agree on how to number a turn
— turn_id in the transcriber, sequence_id in the model. The timeline
reconciles them by id where the ids line up and by position where they do not,
which is why a turn number here is the turn of the conversation rather than
any one service's counter.

