Phone tokens
Short-lived tokens that let an end-user place a call from a browser or mobile softphone. Your API key never reaches the client. See the Browser SDK token flow for the full picture.
Mint a token
Section titled “Mint a token”POST /phone-tokens/mint
| Field | Type | Required | Description |
|---|---|---|---|
uuid |
string | Required | The end-user’s uuid. |
ttl_seconds |
integer, nullable | Optional | Token lifetime. Default 3600, maximum 3600 (one hour). |
max_concurrent |
integer, nullable | Optional | Simultaneous calls this token allows. Default 1, maximum 10. |
Returns { token: string, phone_token: PhoneToken, iceServers: array }. The token and
iceServers are exactly what the Browser SDK’s authenticate() takes.
# your backend: the secret key stays herecurl https://api.sautipbx.com/api/phone-tokens/mint \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "uuid": "the-end-user-uuid" }'{ "token": "eyJhbGc...", "phone_token": { "uuid": "...", "expires_at": "..." }, "iceServers": [{ "urls": "stun:..." }]}// your backend: the secret key stays hereconst res = await fetch("https://api.sautipbx.com/api/phone-tokens/mint", { method: "POST", headers: { Authorization: "Bearer sk_live_...", "Content-Type": "application/json", }, body: JSON.stringify({ uuid: "the-end-user-uuid" }),});const { token, iceServers } = await res.json();// hand only { token, iceServers } to the browser# your backend: the secret key stays hereimport requests
res = requests.post( "https://api.sautipbx.com/api/phone-tokens/mint", headers={"Authorization": "Bearer sk_live_..."}, json={"uuid": "the-end-user-uuid"},)data = res.json()# hand only data["token"] / data["iceServers"] to the browserRefusals
Section titled “Refusals”| Status | Meaning |
|---|---|
402 |
The account cannot fund a call, so the token would be useless. Top up the wallet and retry. |
400 |
The end-user belongs to another account, or is not active. |
404 |
No end-user with that uuid. |
A 402 looks like this:
// HTTP 402{ "detail": "Cannot mint a phone token: insufficient balance. Top up the wallet and retry." }Spendable balance is your wallet balance plus any grace amount and credit limit, so an account running on credit still mints normally. It is the same money test a call is admitted against, which is why a token is refused before it is issued rather than failing on the first call the user makes.
Revoke a token
Section titled “Revoke a token”POST /phone-tokens/revoke
Revoke a token immediately. Body { uuid: string } (the token’s uuid). Returns
{ message: string }.
The PhoneToken object
Section titled “The PhoneToken object”| Field | Type | Description |
|---|---|---|
uuid |
string | Token identifier (use with revoke). |
end_user |
string | The end-user’s uuid. |
extension_number |
string | The end-user’s extension. |
max_concurrent |
integer | Concurrent-call limit. |
is_valid |
boolean | Whether the token is still usable. |
expires_at / revoked_at / created_at |
string, nullable | ISO-8601 timestamps. |