Skip to content

API reference

Access tokens

An access token is a short-lived JWT, minted on your server, that a browser or mobile WebRTC client presents to register a softphone and place or receive calls. Your long-lived API key signs the request but never leaves your backend — the client only ever holds the disposable JWT. Tokens carry a voice grant and a tight TTL, so a leaked token expires in minutes and grants nothing beyond voice. The underlying short-lived-JWT model and WebRTC softphone are shipped in Dial; this public token-minting endpoint is in developer preview.

Server-side only

This endpoint is authenticated with your $TELVOX_API_KEY and must be called from your backend. Never ship the API key to a browser or mobile app. The pattern is: your client authenticates to your server, your server mints a token scoped to that user, and you return only the JWT. The API secret never reaches the client.

Base URL

access-tokens
https://api.telvox.dev/v1

Token properties

A minted access token is represented by the following fields.

PropertyTypeDescription
tokenstring (JWT)The signed JWT your client presents to register the WebRTC softphone. Short-lived; treat it as a bearer credential.
identitystringThe client identity encoded in the token — your own opaque user reference (e.g. agent-204). Used to address inbound calls to this client.
grantsobjectThe capabilities embedded in the token. Currently a single voice grant; see the grant schema below.
ttlintegerLifetime in seconds. Defaults to 600 (10 minutes); capped at 900 (15 minutes). Mint a fresh token rather than issuing long-lived ones.
expires_atstringISO 8601 timestamp when the token expires. After this the client must request a new token from your server.

Voice grant schema

The grant is what a token authorizes. Connect tokens carry a single voice grant — there is no broad account access embedded in the JWT.

Grant fieldTypeDescription
voicerequiredobjectEnables placing and receiving calls over WebRTC. Presence of this grant is what makes the token a voice token.
voice.incoming_allowedbooleanWhether calls may be routed to this client identity. Defaults to true.
voice.answer_urlstringOptional answer URL applied to outbound calls this client originates, overriding the application default.

Mint an access token

POST/v1/access-tokens

Issue a short-lived JWT with a voice grant for a single client identity. Call this from your server.

POST/v1/access-tokens
# SERVER-SIDE ONLY — never expose $TELVOX_API_KEY to the browser
curl -X POST https://api.telvox.dev/v1/access-tokens \
  -H "Authorization: Bearer $TELVOX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "identity": "agent-204",
    "grant": "voice",
    "ttl": 600
  }'
201 created
ParameterTypeDescription
identityrequiredstringYour opaque client identity. Becomes the addressable handle for this WebRTC client.
grantstringGrant to embed. Only "voice" is supported. Defaults to "voice".
ttlintegerRequested lifetime in seconds. Clamped to the 900s maximum.
incoming_allowedbooleanAllow inbound calls to be routed to this identity. Defaults to true.
Response
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6...",
  "identity": "agent-204",
  "grants": {
    "voice": { "incoming_allowed": true }
  },
  "ttl": 600,
  "expires_at": "2026-06-21T17:14:11Z"
}
201 created

TTL & rotation

Tokens default to a 10-minute TTL and are capped at 15 minutes. Rather than extending a token's life, have the client request a fresh one from your server shortly before expires_at. Short lifetimes keep the blast radius of a leaked token to minutes, and rotation happens entirely through your own authenticated endpoint.

Client usage

The client never calls TelVox to obtain a token. It fetches the JWT from your server and hands it to the WebRTC client to register.

client.js
// The client fetches a fresh token from YOUR server, never from TelVox.
const { token } = await fetch("/token").then((r) => r.json());

// Hand the JWT to the WebRTC client to register the softphone.
const device = new TelVox.Device(token);
await device.register();

// Refresh before expiry — request a new token from your server.