
What "Deprecated API usage is no longer supported" means
If a Retell integration started failing with Deprecated API usage is no longer supported: Legacy list endpoints, your code is calling a list endpoint Retell has switched off. The fix is to move POST /v2/list-calls to POST /v3/list-calls (and GET /list-agents to POST /v2/list-agents), read results from items, and page with pagination_key. That part takes five minutes. The parts that break quietly afterwards, like transcripts, filters and older SDKs, take longer, so we tested them against a live workspace.
Our own reporting script got a 200 from POST /v2/list-calls on October 17, 2026. On October 29 the same request returned this:
{"status":"error","message":"Deprecated API usage is no longer supported: Legacy list endpoints. Migration details: https://docs.retellai.com/deprecation-notice/2026/06-15_legacy_list_endpoints"}
The deprecation notice is dated June 15, 2026. So the date on a notice isn't necessarily the day your integration breaks. If you got the "action required" email and put it off because nothing had failed yet, it's probably failing now.
Which Retell endpoints are switched off?
We called every legacy list endpoint and its replacement on October 29, 2026. Every legacy one returned HTTP 400, not 404 or 410, so retry logic won't loop on it, but alerting that only watches for 5xx won't catch it either.
POST /v2/list-calls→ 400. UsePOST /v3/list-calls(200).GET /list-agents→ 400, with a different message pointing to the July 31 agent list notice. UsePOST /v2/list-agents(200).GET /list-phone-numbers→ 400. UseGET /v2/list-phone-numbers(200).GET /list-retell-llms→ 400. UseGET /v2/list-retell-llms(200).GET /list-conversation-flows→ 400. UseGET /v2/list-conversation-flows(200).GET /list-chat→ 400. UsePOST /v3/list-chats(200). Method and path both change.
GET /list-voices and GET /list-knowledge-bases still answered normally. Endpoints that act on one record, like create-phone-call and get-call, aren't part of this change.
Watch the method on agents. GET /v2/list-agents returns a 404 HTML page that says Cannot GET /v2/list-agents. It's a POST now. That 404 looks like a wrong path, so people go hunting for a v3 that doesn't exist.
Why your transcripts disappeared after migrating
This is the one that hurts reporting jobs. POST /v3/list-calls doesn't return transcripts. Across 427 calls in our workspace, transcript and transcript_object were empty on every single row. Call analysis, cost, latency, disconnection reason and metadata are all still there.
To get transcripts you fetch each call:
GET /v2/get-call/{call_id}returned the same fields as the v3 row plus exactly three more:transcript,transcript_objectandtranscript_with_tool_calls.GET /v1/get-call/{call_id}, which the list-calls docs page mentions, returned a 404 for us. So did/get-call/{call_id}. Use v2.recording_urlwas still present on 316 of 427 v3 rows (the ones with a recording), even though the docs say v3 omits it. We'd still read it from get-call in new code, since the docs say it can go away.
That turns one list request into one list request plus one request per call. Sequentially, 20 get-call requests took 4.3 seconds. With eight in flight they took 1.3 seconds. When we ran a 90-day pull right after our other tests, one request came back 429 Too many API requests, you are being throttled. A plain exponential backoff absorbed it, and a rerun saw zero 429s. Build the retry in from day one.
If you only need transcripts for analysis, it's often simpler to stop pulling them at all and process the call_analyzed webhook as calls finish. We covered that pattern in routing Retell post-call analysis into a CRM.
Do your old filters still work on v3?
Some do, some fail loudly, and one fails silently. Here's what we sent to POST /v3/list-calls:
- Old
"agent_id": ["agent_..."]array: still works. It returned the same 228 calls as the new"agent": [{"agent_id": "agent_..."}]shape. - Old
"start_timestamp": {"lower_threshold": ...}: 400,start_timestamp must have required property 'type'. The new shape is{"type": "range", "op": "bt", "value": [from_ms, to_ms]}. - Old
"call_status": ["ended"]: 400,call_status must be object. The new shape is{"type": "enum", "op": "in", "value": ["ended"]}. - A misspelled key (
"agnt"): 200, with all 427 calls. No warning.
That last one matters. A typo in a filter doesn't narrow anything, it hands back your entire call history. If that list feeds a follow-up SMS job, a CRM sync or a cleanup script, a typo means every caller in the workspace. Assert on the result. If you filtered by one agent, check that every returned agent_id matches before acting on the rows.
Unknown top-level keys are ignored the same way. The new filters are also more capable than the old ones: you can filter by direction, disconnection_reason, in_voicemail, call_successful, cost, p50 latency, dynamic variables, metadata and custom analysis fields, which removes a lot of client-side filtering.
How pagination works on v3 list-calls
The response is { items, has_more, pagination_key }. What we saw:
limitmaxes out at 1000. 1001 returnslimit must be <= 1000.limit: 0silently gives you 50, the default, withhas_more: true. Don't compute limits that can hit zero.skipandpagination_keytogether return a 400 with the unhelpful messagerequest/body must NOT be valid. Use one or the other.- Both styles are complete. Walking 427 calls at 100 per page with
pagination_keytook five requests, andskipgave the identical set. No duplicates, nothing missing. - No empty trailing page. Asking for exactly 427 returned
has_more: false. include_total: trueadds atotalcount, but Retell's docs say it costs an extra aggregate query, so only ask when you need it.
The agents endpoint doesn't follow the same rules. On POST /v2/list-agents, a limit in the JSON body was ignored (we sent 2 and got all 12 agents). As a query string, ?limit=2, it worked: two items and a pagination_key. Retell's docs describe it as a list of unique agents covering voice and chat together, so to get the old voice-only list, filter on channel.
The migration snippet we tested
This is the Node 18+ version we ran against our workspace. It pulls the last seven days of ended calls, follows pagination_key, then fetches transcripts eight at a time with a retry on 429:
const KEY = process.env.RETELL_API_KEY;
const BASE = "https://api.retellai.com";
async function retell(path, body, attempt = 0) {
const res = await fetch(BASE + path, {
method: body === undefined ? "GET" : "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: body === undefined ? undefined : JSON.stringify(body),
});
if (res.status === 429 && attempt < 5) {
await new Promise((r) => setTimeout(r, 1000 * 2 ** attempt));
return retell(path, body, attempt + 1);
}
if (!res.ok) throw new Error(`${path} ${res.status}: ${await res.text()}`);
return res.json();
}
async function listAllCalls(filter_criteria = {}) {
const calls = [];
let pagination_key;
do {
const page = await retell("/v3/list-calls", {
limit: 1000,
filter_criteria,
...(pagination_key && { pagination_key }),
});
calls.push(...page.items);
pagination_key = page.has_more ? page.pagination_key : undefined;
} while (pagination_key);
return calls;
}
// v3 rows have no transcript: fetch it per call, 8 at a time
async function withTranscripts(calls, concurrency = 8) {
const out = [];
for (let i = 0; i < calls.length; i += concurrency) {
const batch = calls.slice(i, i + concurrency);
out.push(...(await Promise.all(batch.map((c) => retell(`/v2/get-call/${c.call_id}`)))));
}
return out;
}
const since = Date.now() - 7 * 24 * 60 * 60 * 1000;
const calls = await listAllCalls({
call_status: { type: "enum", op: "in", value: ["ended"] },
start_timestamp: { type: "range", op: "bt", value: [since, Date.now()] },
});
const full = await withTranscripts(calls);
The same logic works in an n8n Code node. If you'd rather keep an HTTP Request node, its pagination option can send pagination_key back in the body until has_more is false. Either way, add the error branch described in our n8n error handling guide, because a 400 from Retell otherwise just stops the workflow and nobody hears about it.
Which Retell SDK version do you need?
If you use the official SDK, you don't touch paths, you upgrade. We downloaded the published packages and checked which endpoints each version calls:
- Node
retell-sdk:call.list()moved to/v3/list-callsin 5.23.0 (May 11, 2026).agent.list()moved to/v2/list-agentsin 5.41.0 (July 2, 2026). - Python
retell-sdk: the same switches landed in 5.36.0 (May 11, 2026) and 5.54.0 (July 8, 2026).
So a project pinned somewhere in between, which is common, has list-calls working and agents failing. Anything on 4.x calls all the removed endpoints. The current release is 6.2.14 (October 27, 2026). Since 6.0 is a major version, read the changelog and re-run your tests rather than bumping blind.
The other deprecation in the same notice
The same notice removes three agent fields: analysis_summary_prompt, analysis_successful_prompt and analysis_user_sentiment_prompt. They now live in post_call_analysis_data as system-presets items named call_summary, call_successful and user_sentiment, with your prompt in description. We didn't change our production agents to test this one, so treat it as Retell's documented behavior. If your provisioning scripts create agents from a template, check the template, because a removed field there will fail every new client setup.
A 10-minute migration checklist
- Search for callers. Grep code, n8n exports and cron scripts for
list-calls,list-agents,list-chat,list-phone-numbers,list-retell-llmsandlist-conversation-flows. In our own n8n instance, the only workflows touching Retell's API usedcreate-phone-call, which isn't affected, so the damage was limited to scripts. - Upgrade the SDK or swap the paths using the list above. Remember
list-agentsandlist-chatsare POST now. - Read
itemsand loop onpagination_key. - Rewrite filters in the typed format and add an assertion that the results match the filter.
- Fetch transcripts with
/v2/get-call, with limited concurrency and a 429 retry, or move to webhooks. - Alert on 4xx, not just 5xx, for every scheduled job that talks to a vendor API.
Broken list calls fail quietly: the first symptom is usually a report with last week's numbers missing. If your voice agents also feed attribution, it's worth checking the downstream side too. Our guide on AI voice agent call tracking and attribution covers where those numbers come from.
How we tested this
On October 29, 2026 we called every legacy Retell list endpoint and its replacement with our own workspace's API key (12 agents, 427 calls), then ran about 30 request variations against POST /v3/list-calls, POST /v2/list-agents and GET /v2/get-call: old and new filter shapes, a misspelled key, limits of 0, 427, 1000 and 1001, both pagination styles, and sequential versus parallel get-call timing. We downloaded the Node and Python retell-sdk packages from npm and PyPI and binary-searched the versions to find where each endpoint changed. The JavaScript snippet above was run against the live API before publishing (18 calls in the 7-day window, all with transcripts). We didn't publish any call content, agent names or phone numbers. Endpoint replacements are from Retell's legacy list endpoints notice.
Get a Free Automation Audit
If your voice agents, reporting jobs or CRM syncs depend on Retell's API and you're not sure what's still calling the old endpoints, get a Free Automation Audit. We'll find every integration that broke or is about to, and fix the ones that fail quietly. You can also see how we build and run voice AI agents for agencies and service businesses.
