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 a400: 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 nogranularity 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.
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.