Every call an agent handles, inbound or outbound, becomes a conversation once it ends. You can read conversations through the API, or have Telvana push each one to you with a webhook. Most integrations use the webhook and keep the API for lookups and catching up.
Read one call
curl "https://api.telvana.com/conversation/<conversationId>" \
-H "x-api-key: $TELVANA_API_KEY"
{
"data": {
"id": "clx8y9z1a2b3c4d5e6f7g8h9i",
"dateInitiated": "2026-10-06T17:04:11.000Z",
"agentId": "jm1u1cawc7dka1x84mrjvb4y",
"direction": "OUTBOUND",
"summary": "Dana confirmed the 2:30 PM pickup.",
"durationSeconds": 48,
"cost": 12,
"humanPhoneNumber": "+15557654321",
"agentPhoneNumber": "+15551234567",
"sentimentClassification": "POSITIVE",
"transcript": "AI: Hi Dana, ...",
"tags": ["appointment_booked"],
"recordingUrl": "https://..."
}
}
The values above are illustrative. A few fields need a word of explanation:
- cost is the call's cost in cents.
- sentimentClassification is POSITIVE, NEUTRAL or NEGATIVE, or N_A when no person was reached.
- tags are labels Telvana's call analysis applied, from the built-in set and any custom tags you defined under Settings, then Tags.
- recordingUrl is a signed link that expires an hour after your request. Download the recording within the hour, or fetch the conversation again for a new link.
A conversation is written when its call ends. Until then the response is 200 with "data": null, which is also what you get for an id that isn't in your workspace.
List calls
GET /conversations returns calls newest first and takes these filters as query parameters:
| Parameter | What it does |
|---|---|
| datetime_start, datetime_end | Only calls that started in this window, as Unix timestamps in milliseconds |
| agent_id | Only one agent's calls |
| direction | INBOUND or OUTBOUND |
| sentiment | POSITIVE, NEUTRAL or NEGATIVE |
| limit | Calls per page, 50 by default and 100 at most |
| skip | How many calls to skip, for paging |
curl "https://api.telvana.com/conversations?direction=INBOUND&datetime_start=1791273600000&limit=100" \
-H "x-api-key: $TELVANA_API_KEY"
The response is { "data": [ ... ] }. To read every call in a window, raise skip by limit until a page comes back with fewer than limit calls:
async function listCalls(params) {
const calls = [];
const limit = 100;
for (let skip = 0; ; skip += limit) {
const query = new URLSearchParams({ ...params, limit, skip });
const response = await fetch(
`https://api.telvana.com/conversations?${query}`,
{ headers: { "x-api-key": process.env.TELVANA_API_KEY } },
);
if (!response.ok) throw new Error(`Telvana answered ${response.status}`);
const { data } = await response.json();
calls.push(...data);
if (data.length < limit) return calls;
}
}
New calls arrive at the top of the list while you page, so when you sync on a schedule, fix the window with datetime_end as well as datetime_start.
What the tags mean
GET /tags returns the built-in tags and what each one means, as an object of tag name to description:
curl "https://api.telvana.com/tags" \
-H "x-api-key: $TELVANA_API_KEY"
Use it to map tags to statuses in your own system, for example moving a lead forward when a call is tagged as booked.