Skip to main content
An execution is the record of one call. The same payload is returned by Get execution, pushed to your webhook, listed by Get agent executions, and shown as Raw Call Data in Call History. It carries the call record, the billing record and the diagnostic record in one object. Most integrations need a dozen of its keys. This page groups them by what they are for.
List endpoints return a trimmed projection: id, status, conversation_duration, created_at and a short telephony_data. Fetch the execution by id, or receive it on a webhook, to get everything below. A payload can also contain keys that are not listed here; those are internal and carry no compatibility guarantee, so do not build on them.

Before you build on this

Three things account for most of the bugs people hit reading this payload.

Nothing is final until the status is terminal

conversation_duration, total_cost, telephony_data.recording_url, transcript and extracted_data are null, 0 or empty until the call finishes and post-processing runs. Read them earlier and you will record zeros. See the status lifecycle.

status: "completed" does not mean a conversation happened

status is derived from the telephony provider’s call-lifecycle field, not from the hangup cause, so a call the callee rejected can still arrive as completed. Check conversation_duration > 0 before treating a call as answered. telephony_data.hangup_reason and hangup_provider_code carry the real ending.

A webhook fires several times for one call

Bolna POSTs this payload as the call’s status changes, so a single call produces multiple deliveries carrying the same id. Make your handler idempotent and key it on id, or you will count the same call more than once. Together those three give the shape of a correct handler: ignore non-terminal deliveries, then decide what actually happened before recording anything.
Handling a delivery
handle is keyed on execution["id"], so a repeated delivery for the same call overwrites rather than duplicates. That is what makes it safe against point 3.

A complete payload

A real completed call. The agent’s welcome message played, the caller never spoke, and the agent hung up after its silence timeout.
Completed execution

Identity and linkage

Status and lifecycle

Timing

created_at and initiated_at differ by the queue wait. Use initiated_at when measuring dial-to-answer behaviour, and created_at when reconciling against the moment you made the request. Scheduled calls also use the statuses scheduled and rescheduled, which sit before queued.

Conversation content

Telephony

All under telephony_data.

Cost

total_cost and cost_breakdown are the billing figures, reported in cents. The dashboard presents the same numbers as credits. See Call pricing.

Usage

usage_breakdown is the unit-level detail behind the cost. Read it when you want to know why a call cost what it did, or which models actually ran.

Latency

latency_data is the diagnostic record. See Call latencies for how to read it.
If PII masking is enabled on your account, phone numbers, telephony_data.recording_url and the string values inside extracted_data come back as null. The keys are still present, so code that reads them sees null rather than a missing field. Check with your account settings before building on those values.

Transfers, context and retries


Reading the payload well

Check conversation_duration > 0, then look for a line starting with user: in transcript. status alone is not enough, because it comes from the telephony provider’s lifecycle field and can read completed for a call the callee rejected. telephony_data.hangup_reason and hangup_provider_code tell you how it really ended.
Start at cost_breakdown.llm_breakdown, because extractions and summarisation are separate LLM passes on top of the conversation, so an agent with many dispositions costs more per call. Then check usage_breakdown.provider_source: components billing to bolna are charged to your wallet, while ones billing to your own connected key are not.
latency_data.time_to_first_audio is what the caller felt. Split it with the per-component time_to_connect and turns values to see which leg was slow, then compare usage_breakdown.endpointing and incremental_delay against a call that felt fine. See Call latencies.
latency_data.interruption_stats, specifically agent_interrupted_user_count, longest_agent_monologue_ms and barge_in_recovery_rate. The settings that change this behaviour, interruption thresholds and endpointing, live in the Engine tab.
Yes. Set webhook_url on the agent and Bolna POSTs this same payload as the call progresses. Whitelist 13.203.39.153, 13.126.9.249 and 13.202.133.53. See Webhooks.