Your code reads every call.
The transcript, each tool call, the recording and the cost, as plain JSON from one API.
cURL
URL="$ZUMU_API/ v1/ call_session"
curl "$URL/ retrieve/ $ID" \
-H "Authorization: Bearer $ZUMU_TOKEN" \
-H "X-Organization-Id: $ZUMU_ORG_ID" \
--fail-with-body \
| jq .sessionNode.js
const base = `${ZUMU_API}/ v1/ call_session`;
const res = await fetch(`${base}/ retrieve/ ${id}`, {
headers: { Authorization: `Bearer ${token}`,
"X-Organization-Id": ZUMU_ORG_ID },
});
const { session } = await res.json();Python
base = f"{ZUMU_API}/ v1/ call_session"
res = requests.get(f"{base}/ retrieve/ {session_id}",
headers={"Authorization": f"Bearer {token}",
"X-Organization-Id": ZUMU_ORG_ID})
session = res.json()["session"]A single request returns the whole conversation.
Hannah Kerr’s call to Linden Animal Clinic, as your code reads it.
- 1CostThe whole conversation in micros: 03:24 of phone at $0.156 a minute is $0.53.
- 2VariablesWhat the agent collected on the call, as key and value, ready for your own records.
- 3LegsEvery leg of the call in order: the agent’s, and anyone it transferred to, each with its own timing and cost.
- 4TranscriptThe conversation turn by turn, the customer, the agent and your people, with each tool call in place.
- 5Tool callEach call by name and ID. What the agent sent and what came back are one request away.
- 6RecordingA signed link to the audio, issued for each request and valid for one hour.
{
"session": {
"session_id": "3f6c2a91-…",
"status": "ended",
"end_reason": "agent_hangup",
"total_cost_micros": 530400,1
CostThe whole conversation in micros: 03:24 of phone at $0.156 a minute is $0.53. "caller": {
"name": "Hannah Kerr",
"address": "+12125550118" },
"agent": { "agent_name": "Front desk" },
"duration_seconds": 204,
"variables": [2
VariablesWhat the agent collected on the call, as key and value, ready for your own records. { "key": "pet", "value": "Biscuit, beagle" },
{ "key": "appointment",
"value": "Thu 9:40 AM" }
],
"legs": [{3
LegsEvery leg of the call in order: the agent’s, and anyone it transferred to, each with its own timing and cost. "leg_id": "lg_51c0…",
"direction": "inbound",
"duration_seconds": 204,
"transcript": { "items": [4
TranscriptThe conversation turn by turn, the customer, the agent and your people, with each tool call in place. { "speaker": "customer",
"text": "Thursday morning is fine." },
{ "speaker": "system",
"text": "Tool call: book_visit",
"tool_call": {5
Tool callEach call by name and ID. What the agent sent and what came back are one request away. "tool_call_id": "tc_8d41…",
"name": "book_visit",
"duration_ms": "412" } },
{ "speaker": "agent",
"text": "Biscuit is booked for Thursday at 9:40." }, …
] } }],
"has_recording": true6
RecordingA signed link to the audio, issued for each request and valid for one hour. }
}Example · Linden Animal Clinic
Quickstart
From credentials to a tool call in three requests.
A token, then the day’s conversations, then what the agent sent your booking system and what came back.
POST /v1/ auth/ token { "client_id": "<client_id>", "client_secret": "<secret>" } 200
{ "access_token": "eyJhbGciOi…", "token_type": "Bearer" }GET /v1/ call_session/ get ? from_time= 2026-09-22+00:00:00 &to_time=2026-09-23+00:00:00 &page_size=50 200
{ "sessions": [{ "session_id": "3f6c2a91-…", "summaries": [{ "text": "Booked Thu 9:40 AM…" }] }, … ], "has_more": false }GET /v1/ call_session/{session_id} /leg/{leg_id} /tool_call/{tool_call_id}/retrieve 200
{ "tool_call": { "name": "book_visit", "request_text": "{\"slot\":\"Thu 9:40 AM\",…}", "response_text": "{\"visit_id\":\"LV-4471\",…}" } }
Then, on every request
Authorization: Bearer eyJhbGciOi…
X-Organization-Id: <organization_id>Reference
Everything your dashboard does, from your own server.
Each resource with its key routes, all under the one token from the quickstart.
| Resource | What it is for | Key routes |
|---|---|---|
| Sessions & records | Page through a day of sessions, open any one, then fetch its recording link or cost breakdown. |
|
| Analytics | The numbers your dashboard draws, as JSON. |
|
| Agents | Create and change agents, give them MCP servers, price them before launch. |
|
| Phone numbers | Search and buy numbers, or import the ones you hold with Twilio or Telnyx. |
|
| SIP trunks | Bring your carrier: trunks, their endpoints and the destinations they ring. |
|
| Destinations | Where a conversation arrives: the numbers and addresses an agent answers. |
|
| MCP servers | Register your MCP servers, sync their tools, switch each tool on or off. |
|
| Integrations | Connect the calendars, CRMs and helpdesks your agents book into. |
|
| Projects & organization | One project per brand, region or customer, under one organization. |
|
The full reference covers every route, each with its request and response schema.Get the full reference →
What engineers ask first.
How do we get API access?
Your workspace comes with it: a client ID and secret, your organization ID and your API URL, so the quickstart on this page runs as written.
How does authentication work?
OAuth 2.0 client credentials: your server trades its client ID and secret for a bearer token and sends that token, with your organization ID, on every request. The secret never leaves your server.
Should we use REST, the MCP server or webhooks?
REST when your server reads or changes Zumu on its own schedule. The MCP server when a person works with Zumu through an AI assistant. Webhooks when your system should hear about an outcome the moment it is ready. Most integrations use all three.
Can we manage agents and numbers over the API?
Yes. The token that reads your conversations also creates and updates agents, buys or imports their numbers, attaches MCP servers and connects your SIP trunks.
Make your first request this week.
Your engineers get API credentials on your demo call and send their first request before it ends.
GET /200session · 03:24 · $0.53
