Skip to content
Reference

Get started

Overview

Calls API

Call history, headline statistics, one call in full, and live switchboard state.

Four routes, and the last of them answers a different kind of question from the other three — see Live state and history before wiring a console to them.

Base: $LIVEGRID_API_URL. Every route is behind a customer JWT and scoped to one organisation — Authorization: Bearer <customer JWT>. Implemented in server/lg_calls_routes.py.

GET /public/calls#

This organisation's calls, newest first.

QueryDefaultNotes
limit50capped at 200
outcomeequality match
modeequality match
agentmatches agent_name
sincestarted_at >=

outcome and mode are passed through as equality matches rather than validated against a list. The set of valid values is a product decision that changes in the worker, and a stale allowlist here would silently hide new call types.

{
  "calls": [
    {
      "id": "...", "room_name": "support-8f3a21", "region": "sg",
      "agent_name": "livegrid", "mode": "avatar",
      "started_at": "...", "ended_at": "...", "duration_s": 214,
      "participant_count": 2, "outcome": "completed", "source": "web",
      "llm_model": "...", "avatar_provider": "livegrid", "cost_usd": 0.41
    }
  ],
  "count": 1
}

GET /public/calls/stats#

QueryDefaultNotes
days30capped at 365
{
  "window_days": 30,
  "totals": { "calls": 812, "completed": 780, "failed": 19, "open": 13,
              "total_seconds": 149204, "total_cost_usd": 318.44 },
  "latency": { "median_ms": 1614, "p95_ms": 3980 },
  "daily": [ { "day": "2026-09-09", "calls": 41, "seconds": 7210, "cost_usd": 15.02 } ]
}

Median, not mean, and it is the one number here worth arguing about. A single thirty-second timeout drags a mean far enough to make a good hour look bad, and the resulting alarm trains people to ignore the number.

open counts rows with no ended_at. That is not the same as "live" — see Live state and history.

GET /public/calls/<call_id>#

One call, its transcript, and what the agent did.

{
  "call": { "...": "every column of lg_calls" },
  "events": [ { "seq": 1, "at": "...", "role": "user", "text": "...", "latency_ms": null } ],
  "tools":  [ { "at": "...", "tool_name": "lookup_order",
                "arguments_json": "{...}", "result_summary": "...", "success": true } ]
}

A call belonging to another organisation and a call that does not exist both return 404 with the same body. Distinguishing them would tell an unauthorised caller which ids are real.

events may be empty on a call that certainly happened — the transcript is best-effort. Render that as "no transcript", never as "no call". Transcripts

GET /public/live#

What is on the wire right now, asked of the media plane itself. Nothing is read from the database.

{ "reachable": true, "rooms": [ { "room": "support-8f3a21", "participants": 2 } ] }
{ "reachable": false, "rooms": [],
  "error": "UDK_SECRET is not configured, so the control plane cannot be asked." }

Always 200, even when unreachable — the request succeeded; what failed is a dependency, and the body says which. reachable: false is not count: 0, and a console must render them differently.

Up nextAvatars API