Disclosure: I'm Nabeel, founder of VoiceDash, a client portal for Retell agencies. It only supports Retell today, which is worth knowing before you read a Retell vs Vapi piece from me.
TL;DR: Most Retell vs Vapi comparisons stop at voice quality and per-minute price. For an agency, the harder question is what happens when every client needs their own data, their own keys and their own login. Retell gives you hard isolation through workspaces but no API to create them. Vapi gives you a flexible server URL priority stack and reusable credentials, but you design the tenant boundary yourself. Both are workable; they push the multi-tenant work into different places.
The question this answers
A single developer building one assistant can pick either platform on latency and features. An agency with ten or twenty clients has three extra jobs:
- Keep client A's calls, recordings and numbers away from client B.
- Route every event (call ended, analysis ready, tool call) to the right tenant in your own backend.
- Pull per-client call history for reports, invoices and dashboards.
Below is how each platform shapes those three jobs, using only what their docs say as of November 10, 2026.
Tenant isolation
Retell: workspaces are the hard boundary
Retell's docs describe a workspace as a fully isolated boundary. Inside one workspace live the agents, conversation flows, LLMs, knowledge bases, voices and phone numbers. API keys are scoped to the workspace that issued them. Billing and usage (payment method, credit balance, invoices), members and roles, and webhooks and telephony settings are all per workspace.
Retell's own recommendation for agencies is one workspace per client, with the client's team invited into their workspace under a suitable role.
The catch: Retell does not expose an API to create, delete or switch workspaces. Every new client means a manual step in the dashboard. That is fine at ten clients and annoying at a hundred, so put it in your onboarding checklist instead of pretending it can be scripted.
What this means for your backend: you will hold one Retell API key per client. Store them encrypted, keyed by tenant, and never let a request for tenant A load tenant B's key.
// one Retell key per workspace, resolved per request async function retellFor(tenantId: string) { const key = await secrets.get(`retell:${tenantId}`); // encrypted at rest if (!key) throw new Error(`no Retell workspace linked for ${tenantId}`); return new Retell({ apiKey: key }); } Vapi: you draw the boundary
Vapi's documentation centres on the organization, with server URLs and credentials configured at org, phone number, assistant and tool level. There is no per-client workspace concept in the parts of the docs I read today, so the isolation model is yours to design: separate organizations per client, or one organization with tenant tagging that your backend enforces. Either way, write down which one you chose, because every later decision (keys, webhooks, reporting) depends on it.
Routing events to the right tenant
Retell webhooks
Retell has an account-level webhook (set in the dashboard, applies to every agent without its own) and an agent-level webhook_url. The docs are explicit: if an agent-level URL is set, the account-level webhook is not triggered for that agent. There is no fan-out to both.
Delivery details worth designing around:
- 10 second timeout; if no 2xx arrives, Retell retries up to 3 times. Acknowledge fast and do the work in a queue.
- Verify the
x-retell-signatureheader with the workspace's API key against the raw body, not re-serialised JSON. - Requests come from
100.20.5.228if you want an allowlist as a second check. - Voice events:
call_started,call_ended,call_analyzed,transcript_updatedand four transfer events. For client reports,call_analyzedis usually the one you store, since it carries the post-call analysis.
Because each workspace already maps to one client, a clean pattern is one webhook path per tenant:
app.post("/hooks/retell/:tenantId", rawBody, async (req, res) => { const key = await secrets.get(`retell:${req.params.tenantId}`); if (!key || !Retell.verify(req.rawBody, key, req.header("x-retell-signature"))) { return res.sendStatus(401); } await queue.push({ tenant: req.params.tenantId, event: JSON.parse(req.rawBody) }); res.sendStatus(204); // well inside the 10 s window }); The signature check doubles as a tenant check: a payload signed with client A's key will not verify on client B's path.
Vapi server URLs
Vapi lets you set a server URL in four places, with a strict priority order from the docs:
- Function tool (tool requests go to the tool's own URL)
- Assistant
- Phone number
- Organization-wide (only when nothing else is set)
Events go to exactly one URL in that stack. For tenant routing, setting the URL on the assistant (or the phone number) per client gives you the same one-path-per-tenant shape as above.
Authentication is handled through credentials you create under Integrations > Server Configuration and reference as server.credentialId on an assistant, phone number or tool. Supported types are Bearer token, OAuth 2.0 client credentials, HMAC (with optional timestamp header for replay protection) and the legacy X-Vapi-Secret header.
One caveat that bites agencies building per-call assistants: Vapi only attaches your credential when the server URL comes from saved org configuration. If the URL arrives in the request itself (a transient assistant in POST /call, or assistantOverrides), no credential is sent and credential fields in the payload are redacted. The docs say this applies to organizations created on or after 2026-09-23 (UTC), with older ones on a phased rollout. If you generate assistants on the fly per client, pass auth in server.headers or save the assistant first.
Pulling per-client call history
Retell
POST /v3/list-calls takes a filter_criteria object. Conditions are ANDed; entries in the agent array (each an agent_id with optional version list) are ORed. You can also filter on metadata keys, call_status, disconnection_reason, call_successful, timestamps, duration_ms, combined_cost, custom_analysis_data and more.
-
limitdefaults to 50, maximum 1000. - Page with the opaque
pagination_keyand checkhas_more. Do not sendskipandpagination_keytogether. -
include_total: truereturns a count of all matches. - The v3 response omits transcripts and
recording_url; fetch those per call withGET /v1/get-call/{call_id}.
With one workspace per client, the workspace key already scopes the query. The metadata filter is useful one level down, for example splitting one client's calls by location.
Vapi
GET https://api.vapi.ai/call filters by id, assistantId, phoneNumberId, and created/updated time with Gt, Lt, Ge, Le variants. limit defaults to 100. If several clients share an organization, your tenant filter is effectively "which assistants and numbers belong to this client", so keep that mapping in your own database rather than inferring it from names.
A quick decision table
| Agency need | Retell | Vapi |
|---|---|---|
| Hard per-client isolation out of the box | Workspaces (manual creation) | Design it yourself |
| Scripted client onboarding | Partly (no workspace API) | Assistants, numbers and tools via API |
| Webhook routing | Account or agent level, agent wins | Org, number, assistant, tool; one URL per event |
| Webhook auth | Signature with workspace key | Credentials (Bearer, OAuth 2.0, HMAC) |
| Call history filters | Rich filter_criteria, up to 1000 per page | id, assistant, number, time ranges |
Where Vapi is the better pick: if you want to script assistant and number setup through the API, generate assistants per call, or want OAuth or HMAC on your endpoints without writing signature code, Vapi's model fits better. Where Retell is easier: if you want isolation you cannot get wrong, per-client billing inside the platform, and richer server-side filters for reporting.
For the wider comparison (including Bland, and which platform suits inbound receptionists vs outbound volume), I wrote a longer guide: Retell AI vs VAPI vs Bland: Which Voice AI Platform Should Your Agency Build On in 2026?
Sources, read November 10, 2026: Retell webhooks, Retell list calls, Retell workspaces, Vapi setting server URLs, Vapi server authentication, Vapi list calls.
Drafted with AI assistance and fact-checked against each vendor's docs.