SIP trunks
The partner trunk API creates and manages SIP trunks with your normal API key. Use it to connect a PBX or SIP platform to TelVox, to set up a trunk for each of your own customers, or to create a WebRTC agent seat (a wss trunk) for a browser dialer. You can do the same in the dashboard under SIP Trunks. The dashboard offers TCP or WSS; the API also accepts TLS and UDP.
API stabilityConnect is live. The API is v0.x, so field names may change before v1. Base URL: https://connect.telvox.dev/api. Send Accept: application/json on every request.
Access
SIP trunking is switched on per account by the TelVox team. Until it is, every endpoint on this page returns 403. Requests use the same Bearer API key as the rest of the API (see authentication). You only ever see your own trunks: a trunk ID that is not on your account returns 404, the same as one that does not exist (its body is a JSON message). Your account may have a limit on how many trunks it can hold; past it, creating one returns 422.
{
"error": "This account is not enabled for SIP trunking. Contact your account manager to have it switched on."
}Trunk fields
Every endpoint that returns a trunk uses these fields.
| Field | Type | Description |
|---|---|---|
| id | integer | The trunk's ID. Use it in the paths below. |
| status | string | pending, active, suspended or revoked. See Status values. |
| label | string | null | Your name for the trunk. |
| client_ref | string | null | Your own reference, for example the ID of the customer this trunk is for. |
| endpoint_name | string | Generated by TelVox, for example tk-8f2k3m9q1x7b. It is also the SIP username. It cannot be changed. |
| voice_webhook_url | string | null | Connect POSTs each call that arrives over the trunk here and runs the XML you return. When set, it takes precedence over cli_lookup_url. |
| voice_webhook_method | string | POST (default) or GET. |
| cli_lookup_url | string | null | Asked which caller ID to use for a call from the trunk. Reply with JSON {"callerId": "+91…"} or a full XML <Response>. 5 second timeout; on any failure Connect uses default_caller_id. |
| cli_lookup_method | string | POST (default) or GET. |
| default_caller_id | string | null | Caller ID used when there is no lookup URL or the lookup fails. |
| status_callback_url | string | null | Where status callbacks for calls on this trunk are sent. |
| status_callback_events | string | Space-separated list of events to send. Default completed. |
| status_callback_format | string | null | Read-only. The shape of this trunk's status callbacks, flat by default. The create response may show null. |
| hangup_url | string | null | Stored with the trunk. Connect does not send requests to it today. |
| dual_channel_recording | boolean | Record calls on this trunk with each side on its own channel. Default false. |
| allowed_caller_ids | string[] | null | If set, a caller ID from cli_lookup_url that is not in this list is refused, and Connect falls back to default_caller_id. |
| created_at | string | When the trunk was created (ISO 8601). |
| connection | object | The SIP login. Included on create, fetch and update, not in the list. See below. |
The connection object
What your PBX or softphone needs to register. It includes the SIP password, so keep it on your server.
| Field | Type | Description |
|---|---|---|
| sip_domain | string | The host to register to: your sip_domain if you set one, otherwise the TelVox SIP host. |
| sip_port | string | The SIP port, for example 5060. |
| transport | string | tcp, tls, udp or wss. |
| wss_url | string | null | The secure WebSocket URL for wss trunks (WebRTC agent seats). null for the others. |
| username | string | The SIP username (the same as endpoint_name). |
| password | string | null | The SIP password. null if it cannot be read, in which case rotate it from the dashboard. |
| secret_available | boolean | false when the password cannot be read. |
Status values
A new trunk starts as pending. TelVox then sets it up on the SIP server and it becomes active. Calls only flow once it is active, so fetch the trunk to check before you hand the login to your customer.
| Value | Type | Description |
|---|---|---|
| pending | string | Just created. The login exists, but calls do not flow yet. |
| active | string | Set up on the SIP server. Calls flow. |
| suspended | string | Switched off for now by TelVox. Kept so it can be switched back on. |
| revoked | string | Given up with DELETE. The row and call history are kept. |
List trunks
/api/partner/trunksAll of your trunks, newest first, in one response. The list leaves out the connection object, so no passwords are returned.
curl https://connect.telvox.dev/api/partner/trunks \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Accept: application/json"{
"data": [
{
"id": 42,
"status": "active",
"label": "Acme",
"client_ref": "acme-001",
"endpoint_name": "tk-8f2k3m9q1x7b",
"voice_webhook_url": "https://your.app/voice/inbound",
"voice_webhook_method": "POST",
"cli_lookup_url": null,
"cli_lookup_method": "POST",
"default_caller_id": "+918045670100",
"status_callback_url": "https://your.app/voice/status",
"status_callback_events": "completed",
"status_callback_format": "flat",
"hangup_url": null,
"dual_channel_recording": false,
"allowed_caller_ids": null,
"created_at": "2026-06-22T17:04:11.000000Z"
}
]
}Create a trunk
/api/partner/trunksCreate a trunk. Every body field is optional. TelVox generates the endpoint name, SIP username and password, and returns them in connection.
| Parameter | Type | Description |
|---|---|---|
| label | string | Your name for the trunk. Up to 255 characters, no line breaks. |
| client_ref | string | Your own reference. Up to 255 characters, no line breaks. |
| sip_domain | string | The host shown in the connection details, if you want your own (for example a name you point at TelVox). |
| transport | string | tcp (default), tls, udp or wss. Use wss for a WebRTC agent seat. It cannot be changed later. |
| voice_webhook_url | string | URL that receives calls arriving over the trunk and returns XML. |
| voice_webhook_method | string | POST (default) or GET. |
| cli_lookup_url | string | URL that picks the caller ID for each call from the trunk. |
| cli_lookup_method | string | POST (default) or GET. |
| default_caller_id | string | Fallback caller ID. Up to 32 characters. |
| status_callback_url | string | Where to send status callbacks. |
| status_callback_events | string | Space-separated events, for example "ringing in-progress completed". Default completed. |
| hangup_url | string | Stored with the trunk. Not called today. |
| dual_channel_recording | boolean | Record each side on its own channel. Default false. |
| allowed_caller_ids | string[] | Caller IDs the lookup may return. Each up to 32 characters. |
curl -X POST https://connect.telvox.dev/api/partner/trunks \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"label": "Acme",
"client_ref": "acme-001",
"transport": "tcp",
"voice_webhook_url": "https://your.app/voice/inbound",
"status_callback_url": "https://your.app/voice/status",
"default_caller_id": "+918045670100"
}'{
"id": 42,
"status": "pending",
"label": "Acme",
"client_ref": "acme-001",
"endpoint_name": "tk-8f2k3m9q1x7b",
"voice_webhook_url": "https://your.app/voice/inbound",
"voice_webhook_method": "POST",
"cli_lookup_url": null,
"cli_lookup_method": "POST",
"default_caller_id": "+918045670100",
"status_callback_url": "https://your.app/voice/status",
"status_callback_events": "completed",
"status_callback_format": null,
"hangup_url": null,
"dual_channel_recording": false,
"allowed_caller_ids": null,
"created_at": "2026-06-22T17:04:11.000000Z",
"connection": {
"sip_domain": "<TelVox SIP host>",
"sip_port": "5060",
"transport": "tcp",
"wss_url": null,
"username": "tk-8f2k3m9q1x7b",
"password": "<SIP password>",
"secret_available": true
}
}A bad field returns 422 with message and errors.
Fetch a trunk
/api/partner/trunks/{id}One trunk with its connection object, including the SIP password, so you can show the login again in your own portal.
curl https://connect.telvox.dev/api/partner/trunks/42 \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Accept: application/json"Update a trunk
/api/partner/trunks/{id}Change a trunk's settings. PATCH works the same way. Send only the fields you want to change.
You can change label, client_ref, sip_domain, voice_webhook_url and its method, cli_lookup_url and its method, default_caller_id, status_callback_url, status_callback_events, hangup_url, dual_channel_recording and allowed_caller_ids. The SIP username, password, endpoint name, transport and status cannot be changed here; other fields are ignored. The response is the updated trunk with its connection object.
curl -X PUT https://connect.telvox.dev/api/partner/trunks/42 \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"status_callback_events": "ringing in-progress completed",
"allowed_caller_ids": ["+918045670100", "+918045670101"]
}'Revoke a trunk
/api/partner/trunks/{id}Revoke a trunk. This is a soft delete: the status becomes revoked and the trunk and its call history are kept. There is no API call to undo it.
curl -X DELETE https://connect.telvox.dev/api/partner/trunks/42 \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Accept: application/json"{ "status": "revoked" }WebRTC agent seat login
A WebRTC agent seat is a trunk created with "transport": "wss". A browser dialer signs in to it with a standard SIP-over-WebSocket library such as JsSIP or SIP.js. This endpoint returns everything the dialer needs: the WebSocket URL, the SIP login and fresh TURN servers for strict networks. Call it from your server when an agent signs in and pass the JSON to that agent's browser. It returns 404 for trunks that are not wss.
/api/partner/trunks/{id}/connectionThe browser-dialer login for a wss trunk: wss_url, sip_domain, username, password, secret_available and ice_servers.
curl https://connect.telvox.dev/api/partner/trunks/43/connection \
-H "Authorization: Bearer $TELVOX_API_KEY" \
-H "Accept: application/json"{
"wss_url": "wss://connect.telvox.dev/ws",
"sip_domain": "<TelVox SIP host>",
"username": "tk-3n7v1c8w2p5d",
"password": "<SIP password>",
"secret_available": true,
"ice_servers": [
{
"urls": [
"stun:<STUN host>:3478",
"turn:<TURN host>:3478?transport=udp",
"turn:<TURN host>:3478?transport=tcp",
"turns:<TURN host>:5349?transport=tcp"
],
"username": "<TURN username>",
"credential": "<TURN credential>"
}
]
}ice_servers is ready to pass to the browser as iceServers. The TURN credentials are new on every request and expire, so fetch them each time an agent signs in. If TURN is not available, ice_servers holds only a STUN server.
The seat password reaches the browserThe browser needs the seat's SIP password to register, so it leaves your server. It is a long-lived password, not a short-lived token. Treat it like a secret: only send it to a signed-in agent, keep it out of page source and logs, and give each agent their own seat. If it leaks, rotate it from the dashboard (SIP Trunks), then fetch the new login.