The Observability page in the dashboard is a wall of time-bucketed charts — how many sessions ran, how they ended, how fast the agent answered, and what it all cost. Everything on it comes from a single endpoint, GET /v1/observability, which returns one complete snapshot of a date range. Everything is regional. The snapshot covers the sessions in the region whose base URL you called, and nothing else.

The request

string (date)
First day in the range, YYYY-MM-DD. Defaults to end_date minus six days.
string (date)
Last day in the range, inclusive. Defaults to today in timezone.
string
default:"UTC"
An IANA zone name. It decides where a day starts and ends, and every bucket in the response is local wall-clock time in this zone. An unknown name is a 400.
string (uuid)
Only sessions this agent ran. Every section honours it.
string
voice, video or text. Every section honours it — including latency, which changes meaning. See the traps below.

Seven days, and no more

A range wider than seven days is a 400: date range cannot exceed 7 days. That is a product choice, not a performance ceiling — the queries carry a month comfortably. Seven days is the window in which a change you made is still the change you are looking at. To compare weeks, ask for each week separately. start_date after end_date is also a 400.

Granularity is derived, never requested

There is no granularity parameter. The rule is fixed: range.granularity is "hour" or "day" and tells you which, so you can label an axis without re-deriving the rule. A single day always returns 24 buckets because a chart that stops at the current hour reads as a day that ended early; the hours ahead are zeroes, not gaps. Every series in the response is zero-filled across every bucket in the range. A stacked bar chart with a missing bucket does not draw a gap — it draws the wrong shape.

What comes back

The eight breakdowns in volume

Each is a {series, other_count} object, and each series carries a stable key, a label, a total and one point per bucket. Every breakdown is capped at eight series. The ninth-busiest and everything below it are summed into one series keyed __other__ and labelled Other, and other_count says how many distinct values went into it — 0 when nothing was dropped. A capped chart that did not say so would read as a complete one.
Two things here will give you a wrong number if you skip them.latency.basis differs by channel, and the two must never be averaged together. It is per_turn for voice and video — a sample-weighted mean over every measured turn — and per_call for text, which reports only llm_node_ttft (the model’s time to first token) because LiveKit measures end-to-end latency from speech, which a text session does not have. With no channel filter, latency defaults to voice and video only; latency.channels says which channels it covered.Every rate is over a subset, not over total_sessions. success_rate is over judged_sessions — the calls post-call analysis actually judged. The cost figures are over priced_sessions. Latency is over measured_sessions. Divide by total_sessions yourself and you will report a number nothing in the product means.

Zero traffic is a fact, not a gap

summary.by_channel always lists all three channels, in the order voice, video, text, whether or not any of them ran. A channel at zero and a channel missing from the response are different facts, and only one of them is a problem — so a flat line means no traffic, never a broken channel. The same applies to pending_sessions and unpriceable_sessions in summary. They are separate on purpose: a call still being priced resolves itself, while a call billing could not price is an incident with a message attached, in cost.unpriceable_reasons. See costs.

What is not here

Agent task runs are excluded entirely. A task is an agent nobody talks to, it writes no session row, and none of it reaches this endpoint — not its runs, not its spend. Task spend appears on the task’s own run history, and, for a task drafting an email campaign, on that batch’s page. There is also no per-turn drilldown, no knowledge-base retrieval metric, no webhook delivery metric and no tool-call volume. For a single call, open the call — calls carries all of that at full resolution.

In the dashboard

Observability offers three presets — Today, Yesterday and 7 days — plus a date picker whose bounds move together, so you cannot pick a range the API will reject. The agent and channel filters map to the two query parameters. Picking a single day switches every chart to hourly without you asking.

Calls

One call at full resolution: transcript, tool calls, latency stages, cost.

Costs

Provider spend versus the platform fee, and how to read either.

Close reasons

Every reason a call can end, and what to do about each.

Debugging agents

Symptom-first playbook for when an agent misbehaves.