Org onboarding (the console) triggers provisioning. Your platform backend can
also trigger it through the control-plane API. Each step below is idempotent
and best-effort. Onboarding completes even if one subsystem is briefly
unavailable. A re-run of the bootstrap backfills whatever was missed.
What a tenant gets
Per-tenant SIP + WebRTC endpoints
<org-id>.sip.clutchcall.dev and <org-id>.webrtc.clutchcall.dev resolve
to the engine. The engine routes inbound SIP INVITEs by their leftmost DNS
label.Isolated analytics
A read-only analytics role scoped by a row policy on
tenant_id. Thus a
customer’s reports and CDRs can never read across the tenant boundary.A usage account
A metering account keyed
Tenant=<org-id> and bound to your rating plan.
Thus every rated call debits the correct balance from the first minute.Managed recording storage
A per-tenant object-storage prefix (
<org-id>/) + access keys. If you
leave a customer’s recording target empty, recordings land in managed
storage.starter | growth | scale | enterprise, with your configured tier as the
default). It also mints a per-tenant realtime channel key. Thus CTI events and
screen-pop have a channel from day one.
Provision a tenant
1
Create the org and bootstrap resources
Onboarding creates the org record. It then runs the provisioning steps in
parallel: DNS labels, the isolated analytics role + row policy, the usage
account, storage keys, the entitlement, and the realtime channel. All are
keyed on the new org id.
2
Point trunks and numbers at the tenant realm
Register the customer’s SIP trunk against their realm. Map DIDs to it. The
engine extracts
<org-id> from the leftmost DNS label of each inbound
INVITE as the tenant_id. Thus no slug-to-id translation is ever needed.
See SIP trunking and
number provisioning.3
Publish the tenant's agent config
When a customer saves an agent, the platform hydrates its pipeline config
to the engine, keyed per agent. Provider credentials resolve per tenant
(below). See
runtime configuration.
4
Issue scoped API keys
Mint a key per customer (or per customer-app). Then their backend can drive
calls and stream audio, and it never sees another tenant’s traffic.
Scoped API keys
Programmatic access uses opaque bearer tokens carried asAuthorization: Bearer <key>. The server stores keys hashed (it shows the
raw value once, at creation). Each key carries a scope set. You can give a
key an expiry, and you can revoke it at any time. The token resolves to exactly
one org id. That org id becomes the tenant boundary for every request the key
makes.
string[]
What the key may do, as
product:action strings — for example voice:read,
voice:write, or a wildcard voice:* / *. The server refuses a request
(403) if the key lacks the scope that the endpoint requires.timestamp | null
Optional hard expiry. Expired keys authenticate as invalid.
timestamp | null
Set this to revoke immediately. The audit trail is not deleted.
- TypeScript
- Python
Isolation model
Every layer enforces tenancy, not only the application:- Naming. Each tenant is a distinct SIP realm/AOR host (multidomain
registrar). Thus two customers can both have extension
1001with no collision. - Routing. The engine derives
tenant_idfrom the inbound INVITE’s DNS label. Thus a misdirected trunk cannot land a call in the wrong tenant. - Data. Reports and CDRs are read through a per-tenant analytics role. Its
row policy pins
tenant_id = <org-id>. There is no query path across tenants. - Credentials. Every tenant secret (provider keys, trunk/registrar passwords) is sealed at rest with a key-encryption key. Provider keys are sealed under the org that owns them. Thus only the engine that handles that org can open them. See voice isolation for the media-plane story.
- Keyspace. Per-tenant runtime state (sessions, registrations, sealed credentials, agent config) lives under org-scoped keys that the engine reads directly.
Per-tenant agent config
Each customer configures their own agents: prompt, ASR/LLM/TTS providers, voice, turn-detection, tools. On save, the platform hydrates the agent’s config into a single per-agent blob. The engine reads that blob at session start. The blob survives many concurrent sessions for the same agent. Timeouts and tunables hot-reload, and in-flight calls do not drop. Provider credentials resolve per tenant. Thus customers can bring their own keys or inherit the platform’s. The resolution order at call time is:- Per-agent override — a key set on a specific agent.
- Per-tenant default — the org’s key for that provider.
- Platform fallback — your environment default (if you offer one).
per provider
Each tenant can supply its own
openai / anthropic / gemini /
elevenlabs / deepgram (and peers) credentials. The secret field is sealed
at rest. Only the non-secret routing fields (endpoint, region) stay
plaintext. See
BYO ASR/LLM/TTS and
BYO speech-to-speech.type: "silero" (local VAD,
the cascaded default) or type: "server_vad" (the realtime provider owns
turns). See turn detection.
Billing & usage metering
Two independent meters feed platform billing. Both attribute usage per tenant:- Rated call usage. On each call teardown, the engine sends a CDR (Q.850
cause + duration, keyed by
call_sid). The system rates CDRs against your tenant’s usage account and rating plan. Thus per-minute call spend accrues automatically. The system captures media quality (MOS, jitter, loss) per call at the same time. - Traffic & bandwidth. The engine counts bytes per tenant, per modality as they flow. It drains the counts into a per-minute rollup. That rollup powers the Traffic & Bandwidth dashboard. Voice media bytes are attributed per tenant, per call.
Entitlement tiers gate features and quotas in the control plane. The usage
account meters spend. They are separate controls. A tier promotion does not
change a tenant’s rated usage. A balance top-up does not change their tier.
Related
Build a contact-center platform
Add ACD, skills, VDN/IVR, and supervisor tools on top of tenancy.
Build a voice agent
The single-agent build that each tenant configures.
Platform backend recipe
A runnable backend that provisions and drives tenants.
Runtime configuration
The per-agent pipeline config that each tenant edits.

