Security
Security for integrators
What leaves your infrastructure, how licenses and session tokens work, how revocation is enforced, and the rules to follow when you integrate.
What Tenms keeps, how your credentials work, and the handful of rules that keep a license safe. For the overview, see the security page.
What leaves your infrastructure
| Path | Call audio | Call summary |
|---|---|---|
| In-process SDK (Python wheel, C library) | Never leaves your process | Posted to the control plane only when TENMS_CONTROL_URL is set (reporter=False turns it off) |
Tenms Edge, /v1/stream | Streamed to Edge and processed in memory, frame by frame | Posted by Edge when the call ends |
| ElevenLabs bridge | Caller audio is cleaned on Edge and forwarded to ElevenLabs | Posted by Edge when the conversation ends |
A call summary holds quality and behaviour data for one call: MOS, SNR, echo and ASR risk,
turn and interruption counts, the failure cause and processing times. It contains no audio
and no transcripts. Transcripts you send are used during the call to confirm interruptions
and attribute failures. The full schema is CallSummary.
Credentials
| Credential | Where it lives | Lifetime | Scope |
|---|---|---|---|
License (tenms1.…, lid = lic_…) | Your servers only | Long-lived, until its exp or revocation | Your customer id, the modules you bought, the ElevenLabs agents it may reach, max_sessions |
Session token (lid = ses_…, parent = lic_…) | Browsers and devices | Must be used to connect within 5 minutes; a conversation that started in time can run up to 4 h | The parent’s modules, ElevenLabs agents and limits. It cannot mint further session tokens |
Both are Ed25519-signed and verified offline, so audio never waits on a license check. The control plane returns a license token once, when it is issued, and never stores it. Session tokens are never stored either.
Rules for your integration
- Never put a license in a web page or an app. Anyone who reads it can use it until it
is revoked. Your backend exchanges it for a session token
(
POST https://app.tenms.cloud/v1/session-tokens) and hands only that to the client. - Mint one session token per conversation, just before connecting, and authenticate
your own user before you mint. On
license_expired, mint a new one. - Servers send the token in the header (
Authorization: Bearer …). Browsers cannot set WebSocket headers and use?token=; URLs can end up in proxy and access logs, which is why only 5-minute session tokens should ever appear in one. - Name your ElevenLabs agents. Every bridged conversation runs on Tenms’ ElevenLabs key,
so a license reaches only the agent ids it lists. A license without the list cannot use
the bridge (
403 agent_not_allowed). Ask for explicit ids rather than a wildcard. - Keep SDK licenses short-lived. The in-process SDK verifies offline against vendor keys compiled into the library and the system clock. A revoked SDK license keeps working in-process until it expires (its telemetry uploads are refused), so SDK deployments should use short license lifetimes.
How licenses are enforced
| Path | Enforcement | Revocable mid-call? |
|---|---|---|
Edge /v1/stream and the ElevenLabs bridge | Signature checked on every connection; revocation list; expiry and maximum-duration guards; per-license session and connection-rate limits | Yes: running sessions, including those opened with session tokens, end within one revocation poll (about 90 s measured) |
| Control-plane API | Signature checked on every request; revoked licenses refused | n/a |
| In-process SDK | Vendor keys pinned in the library and the system clock; modules = requested ∩ licensed | No: offline by design, until exp |
Every read and write on the control plane is scoped to the license’s customer. Call ids
are deduplicated per customer, so tenants cannot collide on a call_id.
Limits you may hit
| Limit | Value | Error |
|---|---|---|
| Concurrent sessions per license, per Edge replica | max_sessions claim, else 100 | 429 license_session_limit |
| Connection rate per license | 10 per second, bursts of 20 | 429 rate_limited |
| Session length | 4 h | max_session_duration |
| Audio pacing | up to 1.5 × real time after a 5 s burst; faster input is back-pressured | none (Edge stops reading) |
| A client that stops reading | disconnected after 10 s | none (connection dropped) |
start message | within 10 s of connecting | start_timeout |
Retry rate_limited, at_capacity, draining, server_shutdown and not_ready with
backoff. Never retry license_revoked, invalid_license or agent_not_allowed. The full
list is in the API reference.
The dashboard
The dashboard at app.tenms.cloud accepts your license token and
shows only your customer’s calls. It is served with a Content Security Policy that allows
only its own script (by hash), refuses framing, and sends nosniff and HSTS. The token is
kept in sessionStorage for that tab, or in localStorage if you tick “Remember on this
device”.
Independent review
An independent verifier reviewed the engine, Edge, the control plane and the Python SDK. Every critical and high finding was fixed and has a regression test, among them: licenses now carry a signed list of the ElevenLabs agents they may reach; revocation and expiry end running sessions; the SDK verifies against pinned vendor keys and the system clock; slow or faster-than-real-time clients can no longer hold capacity; ingest is idempotent per customer. A summary is on the security page. For a security review, contact us.