Overview
Four callable surfaces, and which one you want.
Four callable surfaces. They are not alternatives — they sit at different distances from the media, and hold different credentials.
| Surface | Base | Credential | You are |
|---|---|---|---|
| Calls API · Avatars API | $LIVEGRID_API_URL | customer JWT | a console or a backend |
| Webhook and ingest | $LIVEGRID_API_URL | a signature, or a shared secret | another machine |
| Control plane | $LIVEGRID_CONTROL_URL | UDK_SECRET | a service that needs a token |
| MCP tools | $LIVEGRID_CONTROL_URL/mcp | UDK_SECRET | an agent |
| CLI | — | the key pair, locally | a person at a terminal |
Which one you want#
- Placing a call → MCP
start_call, or the CLI for a one-off. - A token for an existing room → MCP
create_call_token, orPOST /token. - Showing somebody their call history → the Calls API. It is the only surface that is tenant-scoped.
- Reacting to a call ending → you do not poll for it; the media server posts to your webhook.
Two things that are true everywhere#
Every response is JSON, including errors, in the shape
{"error": "<what happened>"}. Some carry a hint or a why beside it, and
those are written for the person who has to fix it rather than for a log.
Absence is not an error, and unreachability is not absence. A room that does not exist returns an empty participant list; a switchboard that cannot be reached raises. Any surface that blurs those two is a bug — see Live state and history.
Where the API actually is#
Every route on these pages is implemented in this repository, and each page names the file it came from.
The deployed API answers at the Railway-generated hostname the web app is
configured with — NEXT_PUBLIC_API_URL — and it is healthy:
curl -s https://glorious-serenity-production-d200.up.railway.app/health
# {"service":"livegrid","status":"ok"}
/public/* on that host answers 401 {"error":"Unauthorized"} without a
customer token, which is the correct response and a good sign rather than a
problem.
business.jsonrecordsapi-livegrid.up.railway.appas the API origin and nothing is bound to that hostname — it returns Railway's own{"code":404,"message":"Application not found"}, which is the platform saying no service answers there, not the app returning 404. Checked 2026-09-10. Read the deployment's ownNEXT_PUBLIC_API_URLrather than that field until it is corrected.