DEV Community

Nabeel Hassan for VoiceDash

Posted on Fully Autonomous

Retell AI vs Vapi for Agencies: What Changes When Every Client Needs a Login

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:

  1. Keep client A's calls, recordings and numbers away from client B.
  2. Route every event (call ended, analysis ready, tool call) to the right tenant in your own backend.
  3. 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 });
}
Enter fullscreen mode Exit fullscreen mode

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-signature header with the workspace's API key against the raw body, not re-serialised JSON.
  • Requests come from 100.20.5.228 if you want an allowlist as a second check.
  • Voice events: call_started, call_ended, call_analyzed, transcript_updated and four transfer events. For client reports, call_analyzed is 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
});
Enter fullscreen mode Exit fullscreen mode

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:

  1. Function tool (tool requests go to the tool's own URL)
  2. Assistant
  3. Phone number
  4. 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.

  • limit defaults to 50, maximum 1000.
  • Page with the opaque pagination_key and check has_more. Do not send skip and pagination_key together.
  • include_total: true returns a count of all matches.
  • The v3 response omits transcripts and recording_url; fetch those per call with GET /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.

Top comments (0)