You are building a platform: your customers sign up, configure their own voice agents, plug in their own numbers and provider keys, and you bill them for what they use — all on top of TeleQuick Voice. This page shows how a tenant is isolated end to end, what each tenant gets at provisioning, and where the billing meters sit. The whole model hangs off one stable identifier — the org id. Every tenant resource (DNS label, SIP realm, data rows, sealed credentials, usage account) is keyed on the org id, never on a human-facing slug, so a customer can rename their workspace without moving any infrastructure.
Provisioning is triggered by org onboarding (the console) or by your platform backend calling the control-plane API. Each step below is idempotent and best-effort: onboarding completes even if one subsystem is briefly unavailable, and re-running the bootstrap backfills whatever was missed.

What a tenant gets

Per-tenant SIP + WebRTC endpoints

<org-id>.sip.telequick.dev and <org-id>.webrtc.telequick.dev resolve to the engine. Inbound SIP INVITEs are routed by their leftmost DNS label.

Isolated analytics

A read-only analytics role scoped by a row policy on tenant_id, so a customer’s reports and CDRs can never read across the tenant boundary.

A usage account

A metering account keyed Tenant=<org-id> bound to your rating plan, so every rated call debits the right balance from the first minute.

Managed recording storage

A per-tenant object-storage prefix (<org-id>/) + access keys. Leave a customer’s recording target empty and recordings land in managed storage.
Onboarding also mints an entitlement in the entitlements control plane (tier starter | growth | scale | enterprise, defaulting to your configured tier) and a per-tenant realtime channel key so 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 and fans out 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 keyed on the new org id.
2

Point trunks and numbers at the tenant realm

Register the customer’s SIP trunk against their realm and map DIDs to it. The engine extracts <org-id> from the leftmost DNS label of each inbound INVITE as the tenant_id, so 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, its pipeline config is hydrated 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) so their backend can drive calls and stream audio without ever seeing another tenant’s traffic.

Scoped API keys

Programmatic access uses opaque bearer tokens carried as Authorization: Bearer <key>. Keys are stored hashed server-side (the raw value is shown once at creation), carry a scope set, and can be given an expiry and revoked at any time. The token resolves to exactly one org id, which becomes the tenant boundary for every request it makes.
scopes
string[]
What the key may do, as product:action strings — e.g. voice:read, voice:write, or a wildcard voice:* / *. A request is refused (403) if the key lacks the scope the endpoint requires.
expires_at
timestamp | null
Optional hard expiry. Expired keys authenticate as invalid.
revoked_at
timestamp | null
Set to revoke immediately without deleting the audit trail.
A tenant’s backend instantiates the SDK with its own key — nothing about other tenants is reachable through it:
import { Voice } from "@telequick/sdk";

// One key per customer. Scopes gate what it can do; the key's org id
// is the tenant boundary the control plane enforces on every call.
const voice = new Voice({ apiKey: process.env.TELEQUICK_API_KEY! });

const call = await voice.calls.originate({
  to: "+15551234567",
  from: "+15557654321",
  app: "AI_BIDIRECTIONAL_STREAM",
});
If you build a customer-facing dashboard, mint a short-lived token per browser session rather than embedding a long-lived key. Supervisor attach and browser media legs already work this way.

Isolation model

Tenancy is enforced at every layer, not just in the application:
  • Naming. Each tenant is a distinct SIP realm/AOR host (multidomain registrar), so two customers can both have extension 1001 with no collision.
  • Routing. The engine derives tenant_id from the inbound INVITE’s DNS label, so a misdirected trunk can’t land a call in the wrong tenant.
  • Data. Reports and CDRs are read through a per-tenant analytics role whose 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, and provider keys are sealed under the owning org so only the engine handling 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 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 agent’s config is hydrated into a single per-agent blob the engine reads at session start (it survives many concurrent sessions for the same agent). Timeouts and tunables hot-reload without dropping in-flight calls. Provider credentials resolve per tenant, so customers can bring their own keys or inherit the platform’s. Resolution order at call time:
  1. Per-agent override — a key set on a specific agent.
  2. Per-tenant default — the org’s key for that provider.
  3. Platform fallback — your environment default (if you offer one).
Bring-your-own keys
per provider
Each tenant can supply its own openai / anthropic / gemini / elevenlabs / deepgram (and peers) credentials; the secret field is sealed at rest and only the non-secret routing fields (endpoint, region) stay plaintext. See BYO ASR/LLM/TTS and BYO speech-to-speech.
Turn detection is configured per agent the same way — 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 attributed per tenant:
  • Rated call usage. On each call teardown the engine emits a CDR (Q.850 cause + duration, keyed by call_sid). CDRs are rated against your tenant’s usage account and rating plan, so per-minute call spend accrues automatically. Media quality (MOS, jitter, loss) is captured per call alongside it.
  • Traffic & bandwidth. The engine accounts bytes per tenant, per modality as they flow, drained into a per-minute rollup that 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 knobs — promoting a tenant’s tier does not change their rated usage, and topping up a balance does not change their tier.
See dashboards and call traces for how tenants see their own usage, and deployment models for running this managed vs. on a customer’s own infrastructure.

Build a contact-center platform

Add ACD, skills, VDN/IVR, and supervisor tooling on top of tenancy.

Build a voice agent

The single-agent build that each tenant configures.

Platform backend recipe

Runnable backend that provisions and drives tenants.

Runtime configuration

The per-agent pipeline config each tenant edits.