Telnyx Calling — Full Documentation
TeXML, SIP trunking, UAC connections, WebRTC, and trusted calling. Complete page content for the Calling section of the Telnyx developer docs (https://developers.telnyx.com). Root index: https://developers.telnyx.com/llms.txt · Lightweight index for this section: https://developers.telnyx.com/development/llms/calling-llms-txt.md
Voice API
Getting Started
Source: https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-fundamentals.mdWelcome to the Telnyx Voice API! This guide will walk you through everything you need to start building voice applications with Telnyx, from creating your account to making your first API call.
What You’ll Build
In this guide, you’ll set up a complete voice application that can make outbound calls and be ready to explore advanced features like AI assistants, speech recognition, and media streaming.Prerequisites
Before you begin, make sure you have:- A computer with internet access.
- Basic understanding of REST APIs and webhooks.
- A development environment with your preferred programming language (we’ll provide examples in multiple languages).
- (Optional) A tool like ngrok for local webhook testing.
Create Your Telnyx Account
To get started with the Voice API, you’ll need a Telnyx account. Follow our account creation guide to set up your account and access the Mission Control Portal.Obtain Your API Key
To authenticate your Voice API requests, you’ll need an API key. Follow our API key creation guide to generate and securely store your API key.Set Up Your Webhook URL
To receive real-time events from the Voice API, you’ll need to set up webhooks. Follow our webhook fundamentals guide to configure your webhook URL and create a handler for Voice API events.Buy a Phone Number
To make calls with the Voice API, you’ll need a phone number. Follow our phone number purchase guide to buy a number that will be associated with your Voice API application.Create a Voice API Application
A Voice API Application defines how Telnyx handles calls to and from your numbers.Creating Your Application
- In the Mission Control Portal, navigate to Real-Time Communication > Voice > Programmable Voice.
- Click on the Create Voice App button in Voice API Applications tab.

- Configure your application and click Create.

Application configuration options
- Application name: A user-assigned name to help manage the application.
- Webhook URL: Where Telnyx sends call events, must include a scheme such as ‘https’.
- Webhook failover URL: Backup URL used if primary webhook URL fails after two consecutive delivery attempts.
- Webhook API version: Determines which webhook format will be used, API v1 or v2 (v2 recommended).
- Anchor site: Routes media through the site with the lowest round-trip time to your connection.
- Tags: Create or remove tags associated to this application for organization.
- Enable hang-up on timeout: Hang up calls if no response to webhook within specified time.
- Custom webhook timeout: Time in seconds to wait for webhook response before timing out.
- DTMF type: Touch-tone digit handling method (RFC 2833 recommended).
- Enable call cost: Receive cost information webhooks for billing and reporting.
- Configure the Inbound settings.

Inbound configuration options
- SIP subdomain: Create a custom SIP address (like
yourname.sip.telnyx.com) to receive calls from any SIP endpoint. - SIP subdomain receive settings: Choose who can call your SIP subdomain - anyone on the internet or only your connections.
- Inbound channel limit: Set the maximum number of simultaneous inbound calls allowed for this application.
- Enable SHAKEN/STIR headers: Add call authentication headers to help verify caller identity and reduce spoofing.
- Codecs: Select which audio and video formats your application will support for optimal call quality.
- Configure the Outbound settings.

Outbound configuration options
- Outbound voice profile: Identifies the associated outbound voice profile for call routing and billing.
- Outbound channel limit: Sets the maximum number of simultaneous outbound calls allowed for this application.
- Configure the Numbers settings.

Numbers configuration
This section displays your purchased phone numbers that can be assigned to this Voice API application. You can view number details including status, type (local/toll-free), and purchase date, then select which numbers to associate with your application for handling inbound and outbound calls.- Click Complete, and congratulations! You just created a Voice API app. It will be listed under your Voice API Applications section.

Your First Voice API Call
Congratulations! 🎉 You’ve successfully set up everything needed for your Voice API application. Now comes the exciting part – let’s make your first outbound call and bring your application to life!Making an Outbound Call
Replace the placeholders with your actual values:your_api_key: Your Telnyx API key from the API key section above.your_phone_number: The number you purchased above.destination_number: The number you want to call.connection_id: Your connection_id (which is the Application ID) from your Voice API Application details page.

cURL
Node.js
Python
Understanding the Call Flow
When you make a call, here’s what happens:- Call Initiated: Telnyx receives your API request and initiates the call.
- Webhook Sent: Telnyx sends a
call.initiatedwebhook to your URL. - Call Progress: Telnyx sends additional webhooks as the call progresses (
call.answered,call.hangup, etc.). - Your Response: When the call is answered, you can use Voice API commands to control it (e.g.,
speak, enabletranscription, startrecording). - Call End: Final webhook (
call.hangup) sent when the call completes.
Example Webhook Sequence
1. call.initiatedTesting Your Setup
Make a Test Call
- Ensure your webhook handler is running and accessible.
- Use the API to make an outbound call to your mobile phone.
Common Issues and Solutions
Record and Retrieve Call Recordings
Record Calls
You can enable call recording for Outbound Voice Profiles by configuring your Record Outbound Calls settings in the Mission Control Portal.
Retrieve Call Recordings
You can view and download your call recordings from the Call Recordings page in the Mission Control Portal.
Next Steps
Congratulations! You’ve successfully set up your first Voice API application. Here are some next steps to enhance your application:Explore Advanced Features
- Voice API Commands & Resources: Learn about all available commands like transfer, conference, record, and more.
- Webhook Handling: Deep dive into webhook event handling and best practices.
- Text-to-Speech: Add natural-sounding voice synthesis to your applications.
- Speech-to-Text: Convert spoken audio into text for voice interactions.
- AI Assistants: Build intelligent voice assistants with natural conversations.
- Answering Machine Detection: Automatically detect and handle voicemail systems.
- Media Streaming: Stream real-time audio for advanced processing and analytics.
- TeXML: Use Telnyx TeXML to define complex call flows.
Try Our Tutorials
- IVR System: Build an interactive voice response system.
- Call Center: Create a call center application with queuing.
- Call Tracking: Implement call tracking for marketing campaigns.
Use Our SDKs
Speed up development with our official SDKs:Resources & Support
Documentation
- Voice API Reference: Complete API endpoint documentation.
- WebRTC SDK Documentation: Build browser-based calling.
- Migration Guides: Moving from other providers.
Getting Help
- Support Center: Knowledge base and ticket support.
- Slack Community: Connect with developers and Telnyx team.
- System Status: Check service availability.
- GitHub examples: For code samples.
Ready to build something amazing? You now have all the tools to create powerful voice applications with Telnyx Voice API!
Commands and Resources
Source: https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-commands-and-resources.mdThe following endpoints can be used with the Voice API applications.
Call
Call events
Conference
Connection
Queue
Recording
Custom storage
Recording transcription
Webhooks
Source: https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-webhooks.md
Overview
Voice API webhooks are HTTP callbacks that notify your application in real time when events occur during a call — a call is initiated, audio playback finishes, a recording is saved, and so on. Your application receives a JSON payload for each event and can respond with call control commands to drive the call flow.Webhook delivery
When an event occurs on a call, Telnyx delivers the webhook to your configured URL. If the primary URL fails, the webhook is sent to the failover URL (if configured). For details on retry logic, signature verification, and general webhook behavior, see Webhook Fundamentals.Configuration
Webhooks can be configured at three levels:- Connection webhook config — default webhook URL and settings tied to a Voice API connection in Mission Control.
- Custom webhook config — per-command overrides. Pass
webhook_urlandwebhook_url_methodin any call control command to route that command’s webhooks to a different endpoint. - Events webhook config — advanced configuration that routes specific event types to different URLs.
Configuration parameters
HTTP methods and headers
Methods
- Webhooks use the
POSTmethod by default. Passwebhook_url_methodasGETin a call control command to receive that command’s webhook payloads as URL query parameters instead of a JSON body.
Headers
Every webhook request includes:Webhook payload structure
All Voice API webhooks share a common envelope. Below is an examplecall.initiated payload:
Common fields
Event types
The following event types are fired by the Voice API. Each event type appears in theevent_type field of the webhook payload.
Call state
Audio playback
DTMF and gather
Recording
Answering machine detection (AMD)
Media forking
Queue
Transcription
Streaming
Response codes
Your webhook endpoint’s HTTP response determines whether delivery is considered successful:Debugging deliveries
Use the Webhook Deliveries API to inspect delivery history for your account. You can filter by status, event type, and time range — useful for diagnosing missed or failed webhooks.Best practices
- Return 2xx immediately — acknowledge receipt within a few seconds, then process asynchronously.
- Implement idempotency — webhooks may be delivered more than once. Use the event
idto deduplicate. - Verify signatures — validate the
Telnyx-Signature-Ed25519header to confirm webhook authenticity. See Webhook signing. - Use
command_id— include acommand_idin your call control commands to prevent duplicate command processing. Commands with duplicate IDs within 60 seconds are ignored. - Monitor failures — track failed webhook deliveries and configure a failover URL for critical applications.
Sending Commands
Source: https://developers.telnyx.com/docs/voice/programmable-voice/sending-commands.mdA Voice API command is sent with a
call_control_id. The call_control_id allows a user to communicate to Telnyx the call_leg the user wants to control. It also helps Telnyx route the call to the location where the call is being managed, resulting in the lowest possible latency for Call Control interactions.
Authenticating your Voice API command request
Like all other Telnyx API V2 requests, you must authenticate your Voice API command requests by sending the Authorization header with a value of an API Key. You can read more about API Keys here. Credential Type HTTP Header Format API Key Authorization: Bearer YOUR_API_KEYExample: Sending commands with a key + secret
To answer the call, send a POST request to the/actions/answer endpoint as shown in the example below.
Don’t forget to update YOUR_API_KEY here.
Available commands and their expected Webhooks
Telnyx offers a broad range of commands to enable granular control of your call flows. Below are a list of those commands, and the webhooks the Telnyx Voice API platform will always send in response. When multiple webhooks are listed, you can expect to often, though not always, receive webhooks in the order provided. Command Expected Webhooks Answer call call.answered Bridge call call.bridged for Leg A call.bridged for Leg B Dial call.initiated call.answered or call.hangup call.machine.detection.ended - if answering_machine_detection was requested call.machine.greeting.ended - if answering_machine_detection was requested to detect the end of machine greeting Forking start call.fork.started call.fork.stopped Forking stop call.fork.stopped Gather using audio call.playback.started call.playback.ended call.dtmf.received - you may receive many of these webhooks call.gather.ended Gather using speak call.dtmf.received - you may receive many of these webhooks call.gather.ended Hangup call.hangup call.recording.saved - if the call is being recorded Play audio url call.playback.started call.playback.ended Playback stop command call.playback.ended or call.speak.ended Recording start no webhooks Recording stop call.recording.saved Reject call call.hangup Send DTMF no webhooks Speak text call.speak.started call.speak.ended Transfer call call.initiated call.bridged to Leg B call.answered or call.hangupResponse when sending Voice API commands
When you send a Voice API Command, you will immediately receive an http response. Responses include, but are not limited to: HTTP Status Code Message Description 200 OK The request succeeded. 403 Forbidden The request was valid, however the user is not authorized to perform this action. 404 Not Found The requested resource could not be found. 422 Invalid Parameters The request has invalid parameters or the call is no longer active.Receiving Webhooks
Source: https://developers.telnyx.com/docs/voice/programmable-voice/receiving-webhooks.mdWhen you send a Voice API command and receive a successful response (i.e. 200 OK), you can expect to receive a webhook. The webhook will be delivered to the primary URL specified on the Voice API Application associated with the call. If that URL does not resolve, or your application returns a non 200 OK response, the webhook will be delivered to the failover URL, if one has been specified. In order to minimize webhook delivery time, Telnyx:
- does not enforce the order in which webhooks are delivered
- retries webhook delivery if your application does not respond within a certain time threshold.
- out-of-order webhooks
- simultaneous (or near simultaneous) webhooks
- duplicate webhooks
command_id parameter as part of your commands. Commands with duplicate command_ids within 60 seconds will be ignored.
Webhooks contain a variety of ID fields which describe them and correlate them with calls.
Example: Receiving a Webhook
When you place an incoming call to a number associated with your Voice API Application, you will receive a callback for the incoming call. It should look something like the JSON below:Command Retries
Source: https://developers.telnyx.com/docs/voice/programmable-voice/command-retries.mdUser Applications may encounter the following situations:
- 5XX Error: Telnyx actively monitors and alerts on the rate of 500, 501, 503, or 504 errors.
- Duplicate Webhooks: Identical webhooks may occasionally be delivered.
How to use command retries for better reliability
Telnyx carefully monitors the Voice API platform for 5XX errors, latency, and duplicate webhooks, and actively works to keep all of these to a minimum. For added reliability, there are several steps developers can take to handle 5XX errors, latency, and duplicate webhooks, and automatically retry commands when such issues are encountered:command_id: send a uniquecommand_idparameter as part of your commands. Thecommand_idmust be unique for each command. We suggest using UUIDv4.- Retry on 5XX Errors: If your application receives a 500 error, immediately retry the command.
- Retry on Latency >500ms: If your application fails to receive a HTTP response from Telnyx within 500ms, send an identical command.
Speech-to-Text
Source: https://developers.telnyx.com/docs/voice/programmable-voice/speech-to-text.md
Introduction
In this tutorial, we will cover how to get a speech-to-text transcription of your calls using Voice API and TeXML. Before starting, please ensure your Voice API or TeXML application is correctly configured.Video Tutorial
Learn how to implement real-time Speech-to-Text recognition in your voice applications: This video shows how to capture and process spoken input from callers using Telnyx’s Speech-to-Text API.Supported engines
Telnyx offers several speech-to-text engines that can be used to process the audio from the call into a transcription:- Google (default) - Google speech-to-text engine that offers additional features like interim results.
- Telnyx - In-house Telnyx speech-to-text engine with significantly better transcription accuracy and lower latency.
- Deepgram - Deepgram speech-to-text engine with 3 models (nova-2, nova-3 and flux) that can be set using
transcription_modelsetting. - Azure - Azure speech-to-text engine with a strong support for multiple languages and accents.
- xAI - xAI Grok STT engine with the
xai/grok-sttmodel. - AssemblyAI - AssemblyAI Universal-Streaming engine with the
assemblyai/universal-streamingmodel. - Speechmatics - Speechmatics real-time engine with the
speechmatics/standardmodel. High accuracy with multilingual and bilingual language packs. - Soniox - Soniox real-time engine with the
soniox/stt-rt-v4model. Automatic language detection with interim results and endpointing support. - Parakeet - Self-hosted NVIDIA Parakeet engine with the
nvidia/parakeet-v3model. Automatic multilingual language detection with final transcripts only.
Voice API
The transcription can be enabled for the Voice API calls using a dedicated endpoint in the following way: Don’t forget to updateYOUR_API_KEY here.
TeXML
You can enable transcription on your TeXML calls by including a “ verb in the TeXML instructions:Text-to-Speech
Source: https://developers.telnyx.com/docs/voice/programmable-voice/tts.mdIn this tutorial, you will learn how to get a Text-To-Speech service on your calls using Voice API and TeXML. Before starting, please ensure your Voice API or TeXML application is correctly configured.
Video Tutorial
Watch this comprehensive video demonstration to see Text-to-Speech features in action: This video demonstrates how to use Telnyx’s Text-to-Speech capabilities to create dynamic voice interactions in your applications.Telnyx Ultra
Telnyx Ultra is a next-generation text-to-speech engine delivering ultra-quality voice synthesis with low latency and support for 44 languages. It produces highly natural and expressive speech, making it a great choice for premium voice experiences. You can request Telnyx Ultra voices for your calls using the Voice API:Telnyx internal Text-to-Speech engine
Telnyx provides a high-quality, low-latency Text-to-Speech (TTS) engine, offering a seamless experience for integrating speech synthesis into your calls. The Telnyx TTS engine ensures a clear and natural-sounding voice, making it an excellent choice for real-time voice applications. You can request Telnyx TTS for your calls using the Voice API. Below is an example of how to trigger speech synthesis with Telnyx TTS:Telnyx Natural
Telnyx Natural voices provide enhanced speech quality with improved naturalness and clarity. These voices offer a significant upgrade from basic text-to-speech options, delivering more human-like speech patterns and better pronunciation accuracy. You can request Telnyx Natural voices for your calls using the Voice API:Telnyx NaturalHD
Telnyx NaturalHD voices deliver premium-quality speech synthesis with exceptional clarity and richness. These high-definition voices are ideal for applications where audio quality is critical, such as customer service, media production, or premium user experiences. You can request Telnyx NaturalHD voices for your calls using the Voice API:AWS Polly
Telnyx offers both levels of quality for AWS Polly Text-To-Speech services: neural and standard. The list of voices can be found under the link. It can be requested on the call using the Voice API command similar to:Polly.*-Neural
Before you use it, please take a look at the price list under the link.
Azure AI Speech
Telnyx supports Azure AI Speech as a text-to-speech provider. You can find the list of supported voices and languages at the following link. To use Azure AI Speech, the process is the same as with AWS Polly. Voices should be specified using the following format: Azure.en-CA-ClaraNeural. Azure AI Speech supports two service levels via Telnyx:-
Neural
- These voices use deep neural networks to generate highly natural and expressive speech.
- Ideal for most general applications, they offer high-quality output with support for SSML to customize pronunciation, pitch, rate, and more.
- Example: Azure.en-CA-ClaraNeural
-
Neural HD (High Definition)
- HD voices deliver enhanced clarity and richness for scenarios where audio quality is critical—such as media production or premium customer engagement.
- These voices provide finer prosody control, improved phonetic detail, and natural pauses, yielding more lifelike speech.
- Example: en-US-Emma:DragonHDLatestNeural
ElevenLabs
Users get many voice options with ElevenLabs; however, response latency may exceed what you’d see from AWS Polly or Azure AI Speech. To use the integration, you must provide an API key to your ElevenLabs account. Telnyx offers to store it in a secure storage. The API key can be saved in the following way:speak command should look as follows for the Voice API application:
MiniMax
MiniMax offers high-quality text-to-speech with expressive voices across multiple languages and accents. Thespeak command should look as follows for the Voice API application:
ResembleAI
ResembleAI voices, built on the Chatterbox model, delivering AI voices that preserve emotion, style, and accent for natural sounding delivery. Thespeak command should look as follows for the Voice API application:
Inworld
Inworld offers expressive multilingual AI voices across three models: Mini, Max, and TTS2. Thespeak command should look as follows for the Voice API application:
Rime
Rime offers two TTS models through Telnyx:- Coda (recommended) — Rime’s flagship model (May 2026). LLM backbone with dedicated speech engine, sub-100ms latency, 184 voices, and top-rated quality in human evaluations. Supports English, Spanish, French, Portuguese, German, and Japanese. Voices use the
Rime.Coda.format. - ArcanaV3 — Previous flagship with multilingual codeswitching across 10 languages: Arabic, English, French, German, Hebrew, Hindi, Japanese, Portuguese, Spanish, and Tamil. Voices use the
Rime.ArcanaV3.format.
speak command should look as follows for the Voice API application:
Call Queueing
Source: https://developers.telnyx.com/docs/voice/programmable-voice/queueing-calls.md| cURL | Python |
cURL
In this tutorial you’ll learn how to use the Telnyx Call Queue API to create and manage call queues with just a few API requests. Call Queueing is fully integrated with the Telnyx Voice API, previously called Call Control. This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API.Adding a call to a new or existing queue
A call can be placed into a queue using theenqueue command. Use the queue_name parameter to specify a queue into which the call should be placed.
- If the
queue_namerefers to a queue that already exists, the call will be placed at the end of the queue. - If the
queue_namehasn’t been used before, a new queue with this name will be created and the call will be placed into it.
YOUR_API_KEY here.
If the call for which the enqueue command was issued is bridged to another call leg (i.e. it is in an active conversation with someone) the call will be unbridged.
Bridging an existing call to a queue
Thebridge command can be used to bridge a call to another call waiting in a queue. The queue’s queue_name should be used as the bridge command’s queue parameter.
For example, a customer support agent can be bridged to the first call from a queue of waiting customer calls. If the customer support agent’s active call has a call_control_id 8899ad4a-de6f-11eb-a54c-02420a0d4168 and the support call queue has a name support, the command to bridge the call is as follows:
When a bridge command is issued, the call at the top of the specified queue will be dequeued and a bridge will be attempted.
Dequeuing calls
Calls can be removed from queues in four ways:- Ending the call by any means (e.g. a
hangupcommand, or the call being disconnected by calling parties). - Issuing any command that results in the call being bridged elsewhere (e.g.
bridge,transfer, conferencejoin,refer). - A call is automatically removed from queues if the
max_wait_time_secsparameter was used when adding the call to a queue and the specified maximum waiting time has elapsed. The automatically dequeued call will remain in a parked state and await further call commands. - Sending the
leave_queuecommand with a call’scall_control_idwill remove that call from any queue it is in, leaving it parked awaiting further call commands.
Inspecting queue state
There are a number of endpoints that let you inspect your queues and enqueued calls: Empty queues will automatically be garbage collected after a period of inactivity.Receiving webhooks for call queueing events
The Telnyx API will send you a webhook for every major queue event, i.e.- when a call is put in a queue,
- when a call leaves the queue for some reason.
enqueue command.
Next steps
Now that you’ve set up simple call queueing functionality with the Telnyx Voice API, why not use call queueing to build a contact center? If you’re interested in building something more complex or large-scale, our experts are standing by to help. Contact our team today.Python
In this guide you’ll learn how to use the Telnyx Call Queue API to create and manage call queues with just a few API requests. Call Queueing is fully integrated with the Telnyx Voice API, the Telnyx Voice API. This guide assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API.Adding a call to a new or existing queue
A call can be placed into a queue using theenqueue command. Use the queue_name parameter to specify a queue into which the call should be placed.
- If the
queue_namerefers to a queue that already exists, the call will be placed at the end of the queue. - If the
queue_namehasn’t been used before, a new queue with this name will be created and the call will be placed into it.
If the call for which the enqueue command was issued is bridged to another call leg (i.e. it is in an active conversation with someone) the call will be unbridged.
Bridging an existing call to a queue
Thebridge command can be used to bridge a call to another call waiting in a queue. The queue’s queue_name should be used as the bridge command’s queue parameter.
For example, a customer support agent can be bridged to the first call from a queue of waiting customer calls. If the customer support agent’s active call has a call_control_id 8899ad4a-de6f-11eb-a54c-02420a0d4168 and the support call queue has a name support, the command to bridge the call is as follows:
When a bridge command is issued, the call at the top of the specified queue will be dequeued and a bridge will be attempted.
Dequeuing calls
Calls can be removed from queues in four ways:- Ending the call by any means (e.g. a
hangupcommand, or the call being disconnected by calling parties). - Issuing any command that results in the call being bridged elsewhere (e.g.
bridge,transfer, conferencejoin,refer). - A call is automatically removed from queues if the
max_wait_time_secsparameter was used when adding the call to a queue and the specified maximum waiting time has elapsed. The automatically dequeued call will remain in a parked state and await further call commands. - Sending the
leave_queuecommand with a call’scall_control_idwill remove that call from any queue it is in, leaving it parked awaiting further call commands.
Inspecting queue state
There are a number of endpoints that let you inspect your queues and enqueued calls: Empty queues will automatically be garbage collected after a period of inactivity.Receiving webhooks for call queueing events
The Telnyx API will send you a webhook for every major queue event, i.e.- when a call is put in a queue,
- when a call leaves the queue for some reason.
enqueue command.
Next steps
Now that you’ve set up simple call queueing functionality with the Telnyx Voice API, why not use call queueing to build a contact center? If you’re interested in building something more complex or large-scale, our experts are standing by to help. Contact our team today.Answering Machine Detection
Source: https://developers.telnyx.com/docs/voice/programmable-voice/answering-machine-detection.mdOutbound calls placed with the Telnyx Voice API can be enabled with Answering Machine Detection (AMD, Voicemail Detection). When a call is answered, Telnyx runs real-time detection to determine if it was picked up by a human or a machine and sends webhooks with the analysis result.
AMD settings
Theanswering_machine_detection value when creating an outbound call or transferring an inbound call can be set to one of the following:
Setting
Description
Webhooks Sent
detect
Only detect if answering machine or human.
call.machine.detection.ended
detect_beep
Listens for a final “beep” sound after detecting a machine
call.machine.detection.ended and call.machine.greeting.ended only if a beep is detected
detect_words
After a machine is detected, a 30 second long beep detection will begin. Note the answering machine may still be playing it’s greeting while the 30 seconds is counting down.
call.machine.detection.ended and call.machine.greeting.ended when the beep is detected or at the end of 30 seconds.
greeting_end
Listens for extended periods of silence or a beep in the greeting to determine if a greeting has ended.
call.machine.detection.ended and call.machine.greeting.ended
premium
RECOMMENDED Premium AMD uses advanced speech recognition technology and machine learning to achieve exceptional accuracy in determining whether a call has been connected to a live person or a machine.
call.machine.premium.detection.ended with one of human_residence or human_business or machine or silence or fax_detected or not_sure. If a beep is detected a call.machine.premium.greeting.ended webhook with beep_detected is also sent. If a beep is detected before call.machine.premium.detection.ended, call.machine.premium.greeting.ended is sent. If a beep is detected after call.machine.premium.detection.ended, both webhooks will be sent.
premium_ios_call_screening_detection
Premium AMD with iOS Call Screening support. Use this when calls may be answered by Apple Call Screening and you need to detect the screening prompt before continuing AMD.
call.machine.premium.detection.ended, call.machine.premium.greeting.ended with result=prompt_ended when the screening prompt ends without a beep, and call.machine.premium.call_screening.detected with result=screening when an Apple Call Screening tone is detected.
Sample dial request
iOS Call Screening Detection
Setanswering_machine_detection to premium_ios_call_screening_detection to run Premium AMD with support for Apple Call Screening. In this mode, Telnyx uses Premium AMD first. If the initial Premium AMD result is machine, Telnyx listens for the iOS call-screening prompt to complete or for an Apple Call Screening tone.
When an Apple Call Screening tone is detected, Telnyx sends call.machine.premium.call_screening.detected with result=screening and then restarts Premium AMD on the screened call. If the screening prompt ends without a beep, Telnyx sends call.machine.premium.greeting.ended with result=prompt_ended. Use this webhook as the signal that your application can provide the response to the iOS screening prompt, such as who is calling and why.
Use answering_machine_detection_config.prompt_end_timeout_millis to control the maximum amount of time Telnyx waits for the iOS call-screening prompt to end after Premium AMD initially detects a machine. The default is 30000 milliseconds. The minimum value is 1000 milliseconds and the maximum value is 120000 milliseconds.
Sample dial request with iOS Call Screening Detection
iOS Call Screening Detection order of operations
- Create an outbound call or transfer an inbound call with
answering_machine_detectionset topremium_ios_call_screening_detection. - Receive
call.initiatedwebhook. - Receive
call.answeredwebhook when the call is answered. - Receive
call.machine.premium.detection.endedwith the initial Premium AMD result. - If the initial result is
machine, Telnyx waits for the call-screening prompt to end or for an Apple Call Screening tone. - If the prompt ends without a beep, receive
call.machine.premium.greeting.endedwithresult=prompt_ended. After receiving this webhook, your application can provide the response to the iOS screening prompt, such as who is calling and why. - If an Apple Call Screening tone is detected, receive
call.machine.premium.call_screening.detectedwithresult=screening. - After the screening tone is detected, Telnyx restarts Premium AMD on the screened call. Expect another
call.machine.premium.detection.endedwebhook with the post-screening classification. - If the restarted Premium AMD detects a machine and later detects a beep, expect
call.machine.premium.greeting.endedwithresult=beep_detected.
General order of operations
- Create outbound call.
- Receive
call.initiatedwebhook. - Receive
call.answeredwebhook when the call is answered either by human or machine. - Receive
call.machine.detection.endedwebhook with human/machine status. - Receive
call.machine.greeting.endedwebhook when beep detected or 30 second timeout.
call.hangup webhook.
Webhooks
call.machine.detection.ended
Thecall.machine.detection.ended is sent when Telnyx can make a determination on human or machine.
The data.payload.result will contain the information about the answering machine:
Result
Description
human
Human answered call
machine
Machine answered call
not_sure
Recommended to treat as if human answered.
Sample Webhook
call.machine.greeting.ended
If theanswering_machine_detection was set to detect_beep, detect_words, greeting_end you could receive a final webhook when the prompt (or beep detection) has finished.
The data.payload.result will contain the information about the answering machine:
Result
Description
AMD Setting
ended
Greeting is over.
ONLY sent when setting is greeting_end
beep_detected
Beep has been detected
detect_beep and detect_words
not_sure
30 second beep detection timeout fired after detecting a machine
detect_beep and detect_words
Sample Webhook
AMD premium Webhooks
call.machine.premium.detection.ended
Thecall.machine.premium.detection.ended webhook is sent when the AMD process can determine whether the call was answered by a human or a machine. It is possible to specify the number of milliseconds that Telnyx should attempt to perform the detection via the total_analysis_time_millis setting. By default, the timeout is set to 30 seconds. If the timeout is reached before the detection is finished, the result in the webhook will be not_sure.
The data.payload.result will contain the information about the answering machine:
Result
Description
human_residence
A human answered the call
human_business
A human answered call
machine
A machine answered the call
silence
No sound was detected
fax_detected
A Fax machine answered the call
not_sure
Not identifiable, or the configured AMD timeout was reached before the result was available.
Sample Webhook
call.machine.premium.greeting.ended
If a machine answered the call, you may receive a final webhook when the beep detection has finished. This webhook is optional and will only be sent if one of two happens:- a beep is detected. In this case, the result is
beep_detected. - the optional AMD timeout is reached after the call was answered by a machine, but no beep was heard. For this case, the result is
no_beep_detected. - the iOS call-screening prompt ends without a beep when using
premium_ios_call_screening_detection. For this case, the result isprompt_ended. After receiving this result, your application can provide the response to the iOS screening prompt, such as who is calling and why.
data.payload.result will contain the information about the answering machine:
Result
Description
AMD Setting
beep_detected
Greeting is over.
ONLY sent when a machine answered the call, and a beep was heard.
no_beep_detected
ONLY sent when a machine answered the call, and the AMD timeout was reached before a beep was heard.
prompt_ended
The iOS call-screening prompt ended without a beep. After receiving this result, your application can provide the response to the iOS screening prompt, such as who is calling and why.
ONLY sent when using premium_ios_call_screening_detection.
Sample Webhook
call.machine.premium.call_screening.detected
Thecall.machine.premium.call_screening.detected webhook is sent when premium_ios_call_screening_detection detects an Apple Call Screening tone. The data.payload.result value is screening.
After this webhook is sent, Telnyx restarts Premium AMD on the screened call. This webhook is not terminal; expect another call.machine.premium.detection.ended webhook with the post-screening classification, and possibly call.machine.premium.greeting.ended if a beep is detected after the restart.
Sample Webhook
Call Recordings Storage
Source: https://developers.telnyx.com/docs/voice/programmable-voice/storing-call-recordings.md
Overview
This tutorial covers how to store your Telnyx call recordings in Amazon S3 or Google Cloud Storage. Call recordings are automatically stored in S3 buckets owned by Telnyx, but users can opt to store recordings in their own S3 or GCS buckets instead.Telnyx’s S3 storage
The recordings for the calls are stored in the S3 buckets owned by Telnyx. The link to them is shared in the webhook “call.recording.saved” when they are ready to download.Using custom GCS storage
As an alternative, the recordings can be stored in a GCS bucket owned by the customer. To set this up, the following requests with user credentials to the storage need to be sent for every particular application:Using custom S3 storage
It is possible to use AWS S3 storage owned by the customer. In that case, the storage configuration can be provided in the following way:Using custom Microsoft Azure Blob Storage storage
The Microsoft Azure Blob Storage can be used for storing recordings too. In that case, the storage configuration can be provided in the following way:Pay
Source: https://developers.telnyx.com/docs/voice/programmable-voice/pay.md
Overview
Telnyx’s Pay over Voice feature enables accepting payments securely over the phone. The feature guides callers through an automated IVR flow to collect payment details (credit card or ACH debit), sends them to the configured payment processor, and returns the result — keeping sensitive card data out of recordings, logs, and AI assistants.How it works
- Create a Payment Connector pointing to the payment processor’s endpoint.
- A Pay session is started on an active call (via Voice API, TeXML, or AI Assistant).
- The caller is guided through IVR prompts to enter payment details via DTMF.
- Telnyx collects, encrypts, and sends the details to the processor.
- The processor charges or tokenizes the payment and returns a result.
- Telnyx emits progress and completed events to the webhook and AI assistant.
Create a Payment Connector
A Payment Connector is the bridge between Telnyx and the payment processor. It stores the processor’s endpoint URL and authentication credentials (encrypted at rest with AES-256).Step 1 — Navigate to Payment Connectors
In the Telnyx Portal, go to Voice API → Applications → Payment Connectors. The portal displays a list of existing connectors:
Step 2 — Create a new connector
Click Create Connector. Fill in the following fields:
When Authentication type is set to
basic, Telnyx sends the credentials as HTTP Basic Auth headers with each request to the processor. The credentials are encrypted with AES-256-CTR before storage and are never exposed in logs or events.
Connectors can also be managed programmatically via the API:
Payment Modes: Test vs Live
Test mode (default)
New connectors are created in test mode. In test mode, the Pay session accepts only a predefined set of test card numbers. Any other card number is rejected with aninvalid-card-number error, and the caller is asked to re-enter the number (up to max_attempts times).
This allows testing the IVR flow, webhook handling, and processor integration end-to-end without processing real payments.
Valid test card numbers
For ACH-debit test mode, any valid-length routing and account numbers are accepted.
Live mode
When ready to accept real payments, switch the connector to live mode. Once a connector is in live mode:- It cannot be edited. The endpoint URL, authentication type, and credentials are locked. This prevents accidental changes to a production payment integration.
- All card numbers are accepted (no test card restriction).
- Real charges are processed through the payment processor.
The Payment Process
When a Pay session starts on a call, Telnyx takes over the call leg and guides the caller through a series of IVR steps. Each step plays a voice prompt, then collects the caller’s DTMF input.Security during payment
Before the first IVR prompt is played, Telnyx automatically disables all processes that could capture payment data:IVR steps
The IVR flow depends on the payment method selected:Credit card flow
ACH debit flow
Custom prompts
Prompts can be overridden by passing aprompts map. Each key is a step name, and the value is either a string or a list of prompt objects with conditional qualifiers:
attempt (1–3), error_type (e.g., invalid-card-number, timeout), card_type (e.g., visa, mastercard, amex, discover).
Error handling and retries
Each step allows up tomax_attempts (default 3) retries. If the caller enters too few digits, the wrong format, or times out, the step is repeated with an appropriate error prompt. If all attempts are exhausted, the session ends with too-many-failed-attempts.
Request sent to the payment processor
Once all digits are collected, Telnyx sends an HTTPS POST to the connector’s endpoint URL with the payment details.Credit card — charge
Credit card — tokenize
Whentransaction_type is tokenize (or amount is 0 or omitted), amount and currency_code are not sent:
ACH debit — charge
Response expected from the payment processor
The processor should return a JSON response: Charge — success:error_code is present and non-empty, the session ends with payment-connector-error.
Using Pay over Voice
Pay over Voice can be triggered from three interfaces: the Voice API, TeXML, and AI Assistant.Voice API
Start a Pay session by sending a POST request to the pay endpoint on an active call:Request parameters
TeXML
Use the “ verb in a TeXML application. This is the simplest way to start a Pay session — include the verb in the TeXML response and Telnyx handles the rest:call_payment_progress and call_payment_completed events. The application can use these to update external systems, confirm the payment, or continue the call flow.
AI Assistant
When using Telnyx’s AI Voice Assistant, a Pay tool can be added to the assistant so it can trigger a payment session during a conversation.
When the AI assistant invokes the Pay tool, it starts a Pay session on the call. The assistant receives
call.payment.progress events after each IVR step and a call.payment.completed event with the final result. This lets the assistant inform the caller of the payment status and continue the conversation naturally.
:::note
During the Pay session, the AI assistant does not receive DTMF input or audio from the caller. The assistant only receives progress and completion events with masked payment data. This ensures the assistant never has access to raw card numbers, CVVs, or bank account details.
:::
Events
Two events are emitted during a Pay session. Both are sent to the configured webhook URL and, if active, to the AI assistant.Payment Progress
Sent after each IVR step completes or fails. Event name:call.payment.progress (API v2) or call_payment_progress (TeXML).
xxx).
Payment Completed
Sent when the Pay session ends (success, failure, or cancellation). Event name:call.payment.completed (API v2) or call_payment_completed (TeXML).
Success:
Result values
Quick reference
Endpoints
Transaction types
SIPREC Server Configuration
Source: https://developers.telnyx.com/docs/voice/programmable-voice/siprec-server.md
Introduction
SIPREC (Session Initiation Protocol Recording) is a standardized mechanism for recording VoIP calls. A SIPREC server, also known as a Session Recording Server (SRS), captures and stores these communications for compliance, quality assurance, and other purposes. This guide provides instructions for setting up and configuring a SIPREC server using Telnyx’s Voice API connection.Setting Up Your SIPREC Server Environment
Step 1: Create a Voice API Application
- Log to the Telnyx portal.
- Navigate to the Voice -> Programmable Voice -> Voice API section.
- Create a new Voice API Application by clicking the “Add New Application” button.
- Configure the application settings as required for your use case. Ensure that you provide a meaningful name and description for easy identification.
Step 2: Assign an Inbound SIP Subdomain
- Within your new Voice API Application, locate the section for Inbound Settings.
- Assign an inbound SIP subdomain to your application. This subdomain will route incoming SIP traffic to your SIPREC server. Example subdomain format:
yourcompany.sip.telnyx.com - Save the changes to apply the new configuration.

Step 3: Configuring the SIPREC Client (SRC)
With your Voice API Application and SIP subdomain set up, the next step is configuring your SIPREC Client (SRC) to interact with Telnyx SIPREC Server (SRS). Please configure your SIPREC Client to use the following Session Recording Server URI:- username: any SIP username can be used, this information will be dropped
- siprec.telnyx.com: is the Telnyx SIPREC server (SRS) domain
X-DestHost
Step 4: Configure SIPREC Token Authentication
SIPREC authentication tokens provide an additional layer of security for SIPREC calls directed to your subdomain application. By implementing these tokens, access to your subdomain voice application is restricted and controlled. Tokens can be created via API by updating the connection settings. Use the following sample API call to create tokens:- Add the token to the SIPREC INVITE request using the
X-Auth-TokenSIP header. - During the SIPREC call setup, the token provided in the
X-Auth-Tokenheader is verified against either of the two configured tokens.
Step 5: Initiating the SIPREC call
When the siprec session starts, two webhooks, one for each of the SIP calls of the media stream will be sent:Step 5: Recording the call
As the next step, the call can be answered and recording can be started using the following Voice API commands:SIPREC call flow
By following this guide, you should have been able to successfully set up and configure your SIPREC client and server sides. This is a typical SIPREC call flow:
- A call is established on the user’s SBC (which has SIPREC SRC capabilities) with RTP streams A and B
- The SIPREC SRC initiates a SIPREC call towards the Telnyx SIPREC SRS (
siprec.telnyx.com), with two RTP streams (A and B) - The Telnyx SRS initiates two SIP calls towards
sip.telnyx.com, one for each RTP stream, and each one witha:sendonly, indicating that RTP is only sent and not received. - Telnyx sends two
call.initiatedwebhooks to the Voice API application URL, one for each of the SIP calls, including thecall_control_idand the metadata from the original SIPREC call (more on this in the next section). - The
call_control_idis used to issue the Voice API commands to answer and record both calls.
SIPREC metadata
Telnyx will pass the metadata that’s included by the SIPREC client on the original SIPREC INVITE message as custom SIP headers on the SIP calls, and each of these will trigger a webhook that contains all of the SIP custom headers. Webhook variables with SIPREC metadata from the INVITE message received by the SIPREC SRS:- to: the content of the SIP URI
- SIP Custom headers: any SIP custom headers will be included in the webhook
- SIPREC XML default metadata: These variables are extracted from the XML metadata and included in the webhook
- DataMode
- ParticipantID
- NameID-AOR
- Associate-Time
- StreamID
- Label
- SIPREC XML custom metadata: any custom variables will also be extracted from the XML metadata and included in the webhook
SIPREC Client
Source: https://developers.telnyx.com/docs/voice/programmable-voice/siprec-client.md
What is a SIPREC client?
SIPREC client (SRC) is a component within the SIPREC framework. The SRC is responsible for initiating and managing the recording session, which communicates to the Session Recording Server (SRS) to send the media streams and metadata for recording.Creating a SIPREC server connector
To create an SIPREC recording session, you need to define an SIPREC server connector that will be used to establish a connection. It can be done using an API request as follows:Creating a SIPREC recording session for Voice API calls
To start a SIPREC recording session you can use the following request:siprec_stop endpoint:
Creating a SIPREC recording session for TeXML calls
To initialize the SIPREC recording session the following TeXML instruction can be used:Gather Using AI
Source: https://developers.telnyx.com/docs/voice/programmable-voice/gather-using-ai.md
Introduction
Gather using AI is a powerful functionality that allows you to efficiently collect specific information from call participants. By leveraging AI, this feature can gather details such as names, addresses, or other relevant information based on a list you provided. The collected data is then sent back in a structured format. This new AI-driven feature offers a much easier user experience compared to the previous gather functionality, simplifying the process and reducing the time needed to collect information. This guide will walk you through the process of using the ‘Gather Using AI’ feature effectively.Prerequisites
The feature can be used for Voice API or TeXML calls similar to regular gather functionality. Please follow the user guides to set up your environment:Voice API
Gather using AI can be enabled for any call by sending the following curl request:parameters section contains all the data that you want to gather during the call. Please use the json schema to define them.
The required section specifies when the gather process should end. A webhook will be sent when all values from this list are gathered. If no values are provided, the process will end as soon as the first value is retrieved.
Message history
It is possible to provide the history of the conversation in themessage_history section, allowing the bot to continue the conversation without losing context
TeXML
In the similar, the gather using AI can be enabled from TeXML. There is a dedicated verb “ that can be used for that purpose:Noise suppression
The crucial part of the gathering process is to have an accurate transcription of what was said during the call. To improve the quality of the transcription, it is recommended to enable noise suppression for the call. This can be done in the following way for Voice API calls:Need more assistance?
If you need some help, reach out to a member of our team through our form or the portal.Attach an AI Assistant to a Call
Source: https://developers.telnyx.com/docs/voice/programmable-voice/ai-assistant-start.md
Overview
Theai_assistant_start command lets you attach a pre-configured AI assistant to an active call. The assistant takes over the conversation, handles speech recognition, and responds using a voice of your choice — no additional infrastructure required.
This is different from Gather using AI, which is purpose-built for collecting structured data. ai_assistant_start is for open-ended, conversational AI experiences.
Prerequisites
- A Telnyx account with an active call in progress. Follow the Voice API getting started guide if you haven’t set that up.
- An AI assistant. You can create one:
- No-code via the Portal: AI Assistants guide
- Via the API: Create an assistant
id (format: assistant-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Start an AI Assistant on a Call
Send aPOST request to ai_assistant_start with the call_control_id of the active call:
Webhooks
Once started, the assistant emits the following webhooks:Stop the Assistant
To stop the assistant and return control to your application:Add a Participant to an Existing Conversation
Once an AI assistant conversation is running, you can bring additional call legs into it usingai_assistant_join. For example, you can dial out to a new destination, wait for the person to answer, then add them to the ongoing conversation.
Prerequisites
- An active AI assistant conversation with a known
conversation_id. Theconversation_idis returned in the200response ofai_assistant_start.
Example: Dial a new participant and add them to the conversation
Step 1 — Dial the new destination:call_control_id for the outbound leg.
Step 2 — Wait for the call.answered webhook:
When Telnyx sends a call.answered event for the new call leg, extract its call_control_id.
Step 3 — Add the participant to the conversation:
Join the Conversation
Once you have the newcall_control_id:
id must be the call_control_id of the call being added. The only supported role is "user".
Optional Participant Fields
Next Steps
- Explore the full AI Assistant API reference
- Configure your assistant in the Portal
- Collect structured data mid-call with Gather using AI
Dialogflow Integration
Source: https://developers.telnyx.com/docs/voice/programmable-voice/dialogflow-es.mdTelnyx’s Dialogflow tutorial will teach you how to create and manage sophisticated voice interactions with your customers. In this tutorial, you will learn how to integrate your instance of Dialogflow ES, so that you can send the audio from the call to it and get the response from your bot plated on the call.
Getting started
In order to do successfully integrate Dialogflow ES with Telnyx Voice API, you’ll need to start by assigning the Dialogflow configuration to your Voice API application using the following update request.Dialogflow Connections request sample
Don’t forget to updateYOUR_API_KEY here.
Enabling dialogflow for outbound calls
Enabling dialogflow for inbound calls
Need some assistance?
If you need some help, reach out to a member of our team through our form or the portal.Real-Time Media Streaming
Source: https://developers.telnyx.com/docs/voice/programmable-voice/media-streaming.mdMedia Streaming provides instant access to your raw call media. With it, you can deliver exceptional customer experiences—from unlocking new insights through sentiment analysis to providing fast resolutions using AI solutions. You can also bring your own AI engine and use real-time media streaming to connect it directly to call control, enabling custom AI-powered voice applications. When your call is established, Telnyx takes the call media and forks it, so recipients receive the call simultaneously. The Telnyx network ensures that call media can be duplicated, delivered, analyzed, and returned in real-time. The secondary delivery recipient never occupies the call stream, so you never have to worry about degraded quality or dropped connections. This guide covers how to set up media streaming over Websockets.
Requesting streaming using Dial Command
The requesting dial command can be extended in the following way to request streaming using WebSockets:- stream_url - the destination address when the stream is going to be delivered.
- stream_track - specifies which track should be streamed, with possible options:
- inbound_track (default)
- outbound_track
- both_tracks
Requesting streaming using Answer Command
Using the same attributes as above, streaming can be requested while answering the call:Streaming process flow
When the WebSocket connection is established, the following event is being sent:Bidirectional media streaming
Sending RTP stream
The RTP stream can be sent to the call using websocket. The functionality can be enabled by settingstream_bidirectional_mode to rtp. For dial command it should look as follows:
RTP stream codec
There are the following codecs supported by bidirectional streaming:- PCMU, 8 kHz (default)
- PCMA, 8 kHz
- G722, 8 kHz
- OPUS, 8 kHz, 16 kHz
- AMR-WB, 8 kHz, 16 kHz
- L16, 16 kHz
Sending media files
Media files can also be sent back to the call through the websocket. This is done similarly to the playback_start command when using a base64-encoded mp3 file in the payload. Send a packet to the websocket connection as follows:- Media payloads can only be submitted once per second.
- Media must be base64 encoded mp3.
Clear message
Sending a clear message will immediately stop the media playing on the stream and clear the media queue.Mark message
Mark messages can be used to keep track of media ending on the stream:- You can send a mark message to the stream after a media message.
- When the media immediately preceding the mark finishes you will receive the same mark back.
DTMF message
In case of DTMF events on the call, the following message will be sent over websocket:occurred_at field is a timestamp captured on the Telephony engine side. These are consumed as asynchronous events and in certain circumstances may arrive out of order. This field can be used to ensure proper order.
Error message
In case of any case of error during media streaming, an error frame in the following format is sent:Example of integration
In the Telnyx GitHub repository there are several examples of integrations with external services using Media streaming:- Simple application that handles websocket streaming and provides the transcription of it using Node JS
- Integration with DeepGram transcription engine using Node JS
- Integration with OpenAI speech-2-speech engine using Node JS
- Pipecat Telnyx Chatbot in Python
Conversation Relay
Source: https://developers.telnyx.com/docs/voice/programmable-voice/conversation-relay.mdConversation Relay connects a live Telnyx call to your WebSocket application. Telnyx handles speech recognition and text-to-speech while your application receives caller input and sends commands back in real time. Use Conversation Relay when you want to build your own conversational voice application, connect calls to an LLM, react to DTMF input, play audio, change languages during a session, or end the relay session from your application. This guide covers how to start Conversation Relay, what WebSocket frames are exchanged, and how to handle callbacks.
How Conversation Relay works
Conversation Relay uses a single bidirectional WebSocket connection per session:- Your application provides a public
wss://WebSocket URL. - Telnyx starts Conversation Relay on the call, either from TeXML or with a Programmable Voice command.
- Telnyx opens a WebSocket connection to your application.
- Telnyx sends a
setupframe that identifies the session and call. - Telnyx sends
prompt,dtmf,interrupt, anderrorframes as call events occur. - Your application sends
text,play,sendDigits,language, orendframes back to Telnyx.
Starting Conversation Relay using TeXML
To start Conversation Relay from a TeXML application, return averb with a nested verb from your TeXML voice URL.
action attribute is configured on , not on . It controls where Telnyx sends the action callback after the connected service stops. Your application can use that callback request to return the next TeXML instructions for the call.
The following attributes configure the relay session:
- url - The WebSocket URL Telnyx connects to. This must start with
ws://orwss://. - welcomeGreeting - Text Telnyx speaks when the relay starts.
- voice - The TTS voice used for generated speech.
- language - The default language for TTS and transcription.
- transcriptionProvider - The speech recognition provider.
- dtmfDetection - Enables DTMF detection and
dtmfWebSocket frames. - interruptible and welcomeGreetingInterruptible - Control when caller input can interrupt speech.
- Language - Adds a supported language with optional per-language
voice,ttsProvider,transcriptionProvider, andspeechModelsettings. - Parameter - Sends custom key-value data to your WebSocket server in the
setupframe.
Starting Conversation Relay using Programmable Voice
You can also start Conversation Relay on an active Programmable Voice call with the Start Conversation Relay command. Use this option when your application is already controlling the call through Call Control. After the call is active, send aconversation_relay_start command with the call’s call_control_id.
- url - The Conversation Relay WebSocket URL.
- greeting - Text Telnyx speaks when the relay starts.
- voice - The TTS voice used for generated speech.
- tts_provider - The text-to-speech provider. If omitted, Telnyx derives it from
voiceorprovider. - voice_settings - Provider-specific voice settings.
- language - The default language for TTS and transcription.
- languages - Per-language TTS and transcription settings.
- dtmf_detection - Enables DTMF detection.
- interruptible and interruptible_greeting - Control when caller input can interrupt speech.
- transcription_engine and transcription_engine_config - Configure the speech recognition provider.
- custom_parameters - Key-value data forwarded to the relay session.
WebSocket process flow
When Conversation Relay starts, Telnyx opens a WebSocket connection to the configuredurl and sends a setup frame:
setup frame to initialize call-specific state in your application. After setup, your application can send text, play, sendDigits, language, or end frames back to Telnyx.
Telnyx does not reconnect automatically if the WebSocket closes. Closing the WebSocket terminates the Conversation Relay session.
Frames sent by Telnyx
Telnyx sends the following frame types to your WebSocket server.Prompt frame
Telnyx sendsprompt frames as the caller speaks:
last: false prompts as interim transcription updates. Use last: true prompts as the final transcript for the caller’s utterance.
DTMF frame
When DTMF detection is enabled, keypad input is sent asdtmf frames:
Interrupt frame
When the caller barges in over TTS playback, Telnyx sends aninterrupt frame:
Frames sent by your application
Your WebSocket server sends the following frame types to Telnyx.Sending text
Send atext frame to speak text to the caller. The text content is sent in the token field.
last: false, then send the final chunk with last: true:
last, Telnyx treats it as false. Send last: true when the turn is complete.
Playing audio
Send aplay frame to play an audio file by URL:
Sending DTMF digits
Send asendDigits frame to send DTMF digits on the call:
0-9, A-D, w or W for a pause, #, and *.
Changing language
Send alanguage frame to change TTS and/or transcription language:
ttsLanguage or transcriptionLanguage must be provided.
Ending the session
Send anend frame to end the Conversation Relay session gracefully:
Continuing the call after Conversation Relay
Theverb runs in synchronous mode. When the nested service stops, Telnyx either continues with the next TeXML instructions in the same response or, when action is set on “, sends a request to that callback URL so your application can return the next TeXML document.
For example, you can provide a follow-up prompt after Conversation Relay ends:
and instructions are already present after “.
If you set action, Telnyx requests the next instructions from your callback URL:
Webhooks
When using Programmable Voice, Conversation Relay lifecycle events are delivered to your Call Control webhook URL. When the relay session ends, Telnyx sends:reason is customer_disconnect.
Error handling
If your application sends malformed or invalid frames, Telnyx sends anerror frame:
Next steps
- Start with
promptframes to react to caller speech. - Send
textframes to stream LLM responses back to the caller. - Use
dtmfandsendDigitsframes to integrate keypad-driven flows. - Use
languageframes for multilingual conversations. - Use
endwhen your application is ready to leave Conversation Relay.
Noise Suppression
Source: https://developers.telnyx.com/docs/voice/programmable-voice/noise-suppression.mdIn this tutorial, you’ll learn how to enable noise suppression for the Voice API and TeXML calls. Noise suppression works for both AI-powered calls (like AI Assistants and Gather Using AI) and regular voice calls. While it improves audio quality across all call types by reducing background noise, the biggest value comes from enhanced AI performance—cleaner audio leads to more accurate speech recognition and better AI responses. This makes noise suppression especially valuable for AI use cases where audio quality directly impacts user experience.
Voice API
The noise suppression can be enabled for the Voice API calls in the following way: Don’t forget to updateYOUR_API_KEY here.
The only parameter required for the request is direction which can have one of the following options: inbound | outbound | both.
Please be aware that the charge is applied for each direction separately.
Supported engines
Telnyx offers four noise suppression engines, each optimized for different use cases:Choosing an engine
- For standard telephony, use
Denoiser(default) orKrispfor speaker isolation. - For WebRTC calls, use
DeepFilterNetfor full-band processing. - For AI-powered calls (AI Assistants, Gather Using AI), consider
AiCousticsfor the best speech recognition accuracy.
noise_suppression_engine parameter:
Engine configuration
Some engines support additional tuning vianoise_suppression_engine_config. Parameters are engine-specific and ignored by other engines.
Krisp models
TheKrisp engine supports three sub-models optimized for different telephony scenarios. Select a model using noise_suppression_engine_config.model:
You can also set the suppression intensity with
suppression_lev (0–100):
DeepFilterNet configuration
TheDeepFilterNet engine supports two tuning parameters:
AiCoustics configuration
TheAiCoustics engine exposes enhancement and gain controls:
TeXML
In TeXML there is a dedicated verb for enabling the noise suppression on the call.Deepfake Detection
Source: https://developers.telnyx.com/docs/voice/programmable-voice/deepfake-detection.mdTelnyx Deepfake Detection analyzes live call audio to determine whether the remote party’s voice is human or AI-generated. When enabled, audio is streamed in real time to a detection model that returns a classification result via webhook. Deepfake detection is available on both outbound calls (Dial) and inbound calls (Answer).
How it works
- You enable
deepfake_detectionwhen dialing or answering a call. - Telnyx streams the remote party’s audio to the detection service.
- The service analyzes audio frames and returns a result within the configured timeout.
- You receive a
call.deepfake_detection.resultwebhook with the classification, or acall.deepfake_detection.errorwebhook if something went wrong.
Configuration parameters
Enabling on an outbound call
Include thedeepfake_detection object when creating an outbound call via the Dial command:
cURL
Node.js
Python
Ruby
Java
Go
PHP
Enabling on an inbound call
Adddeepfake_detection to the Answer command when picking up an incoming call:
cURL
Node.js
Python
Ruby
Java
Go
PHP
Handling the result webhook
When detection completes, you receive acall.deepfake_detection.result webhook:
Result fields
Handling errors
If detection fails, you receive acall.deepfake_detection.error webhook:
Error types
Example: screening inbound calls
This example webhook server answers inbound calls with deepfake detection enabled and takes action based on the result.Node.js
Python
Ruby
Go
Java
PHP
Best practices
- Set appropriate timeouts. The default 15-second detection timeout works well for most calls. Increase it if callers may take longer to start speaking (e.g., IVR prompts on the remote end).
- Use
scoreandconsistencytogether. A high score with high consistency is a strong signal. A high score with low consistency may warrant additional verification rather than an immediate hangup. - Handle errors gracefully. Detection errors should not block the call. Design your application to fall through to normal call handling when detection is unavailable.
Related resources
- Voice API Fundamentals
- Receiving Webhooks
- Answering Machine Detection
- Dial API Reference
- Answer API Reference
IVR
Source: https://developers.telnyx.com/docs/voice/programmable-voice/ivr-demo.md| Python | Node | Ruby |
Python
⏱ 60 minutes build time || GithHub Repo Telnyx IVR demo built on Voice API V2 and Python with Flask and Ngrok. In this tutorial, you’ll learn how to:- Set up your development environment to use the Telnyx Voice API using Python and Flask.
- Build a find me/follow me based app via IVR on the Telnyx Voice API using Python.
- Prerequisites
- Telnyx Voice API Basics
- Call Commands
- Client State
- Building the IVR
- Creating the IVR
- Answering the Incoming Call
- Presenting Options
- Interpreting Button Presses
Prerequisites for building an IVR with Python
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API. You’ll also need to havepython installed to continue. You can check this by running the following:
Telnyx Voice API basics
For the Voice API application you’ll need to get a set of basic functions to perform Telnyx Voice API Commands. The below list of commands are just a few of the available commands available with the Telnyx Python SDK. We will be using a combination of Answer, Speak, and Gather Using Audio to create a base to support user interaction over the phone.- Voice API Bridge Calls
- Voice API Dial
- Voice API Speak Text
- Voice API Gather Using Speak
- Voice API Hangup
- Voice API Recording Start
telnyx, so make sure you have it installed. If not you can install it with the following command:
.env file
This app uses the excellent python-dotenv package to manage environment variables. Make a copy of.env.sample and save as .env 📁 in the root directory and update the variables to match your creds.
load_dotenv() function to set the environment variables.
Server and Webhook setup
Flask is a great application for setting up local servers. However, in order to make our code public to be able to receive webhooks from Telnyx, we are going to need to use a tool called ngrok. Installation instructions can be found here. Now to begin our flask application, underneath the import and setup lines detailed above, we will add the following:
Receiving and interpreting webhooks
We will be configuring our respond function to handle certain incoming webhooks and execute call control commands based on what the values are. Flask catches the incoming webhooks and calls the respond() function every time a webhook is sent to the route we specified as ‘/webhook’. We can see the json value of the hook in the request.json object. Here is what a basic Telnyx Call Object looks likeCall commands
A full reference to the call commands in every Telnyx SDK available can be found hereClient state
Client State: within some of the Telnyx Voice API Commands list we presented, you probably noticed we were including the Client State parameter. Client State is the key to ensure that we can perform functions only when very specific conditions are met on our App while consuming the same Voice API Events.
Because the Telnyx Voice API is stateless and async your application will be receiving several events of the same type, e.g. user just included DTMF. With Client State you enforce a unique ID to be sent back to Telnyx which be used within a particular Command flow and identifying it as being at a specific place in the call flow.
This app in particular will ask the user to make a selection from various Weather stations in the US. Upon their selection, they will be transfered to the city of choice.
The client_state is particularly useful during the transfer, as the outbound leg of the call will also emit status updates to the same endpoint as the inbound call.
Setting a value to the client_state will allow us to check the direction of the call for the gather IVR logic.
Building the IVR
With all the basic Telnyx Voice API Commands set, we are ready to consume them and put them in the order that will create the IVR. For this tutorial we want to keep it simple with a flow that corresponds to the following IVR Logic:- Answer the incoming call
- Present the options to the caller
- Transfer the caller based on their selection
Creating the IVR
In a separate file we can create a simple class to build the Gather strings based on a simple json configuration file. The objective is to separate the IVR functionality from the spoken sentence. This will allow the IVR prompts to be updated without changing Python code.IVR class
Instantiating the IVR class
The app uses a basic JSON configuration fileivrConfig.json
- Read the file
- Covert the JSON to a dict
- Create the class
my_ivr as a global variable for the Flask route to generate prompt strings and check the user pressed digits.
Answering the Incoming Call
Now, we can add a simple Call command to answer the incoming call. Underneath where we check if the event iscall_initiated. To keep track of which call is which; we’ll set the direction to the client_state using pythons native base64 encoding.
👀 At the top ⬆️ of the app.py file add import base64
- Base64encodes the direction value
- Sets as client_state
- actually answers the call.
Presenting options
Now that we have answered the call, we can use theGather Using Speak command to present some options to the user. To do this, we will check the event and check to see that client_state exists. The outbound transferred call leg will also emit the call.answered event; however, the client_state value will be null. Otherwise, the called party would also be presented with the gather prompt.
my_ivr object we created earlier, we can send Gather Using Speak audio to the number. This code present the caller with the generated prompt my_ivr.get_prompt()
Interpreting button presses
Our next check will be to see what digit is pressed when the gather has completed & sends thecall.gather.ended event. We’ll extract the digits from the payload and use our instantiated IVR class to lookup the transfer number.
Finally, we’ll send the transfer command to Telnyx to transfer the user to their destination.
Conclusion
Take a look at the GithHub Repo for a commented version of this code to use as a base for your IVR application!Node
⏱ 60 minutes build time || Github Repo Telnyx Find Me/Follow Me IVR demo built on the Telnyx Voice API V2 and node.js. In this tutorial, you’ll learn how to:- Set up your development environment to use Telnyx Voice API using Node.
- Build a find me/follow me based app via IVR on Telnyx Voice API using Node.
Prerequisites for building an IVR with node
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using Voice API. You’ll also need to havenode installed to continue. You can check this by running the following:
The Basics of Telnyx Voice API
For the Voice API application you’ll need to get a set of basic functions to perform Telnyx Voice API Commands. This tutorial will be using the following subset of basic Telnyx Voice API Commands:- Voice API Bridge Calls
- Voice API Dial
- Voice API Speak Text
- Voice API Gather Using Speak
- Voice API Hangup
- Voice API Recording Start
telnyx, so make sure you have it installed. If not you can install it with the following command:
Auth tab you select Auth V2.
Once you have them, you can include it as ‘const’ variable in your code:
telnyx-config to store this information. Here we will store our API Key as well as our connection ID, the DID associated with that connection and the PSTN DID we will send calls to.
Understanding the use of the SDK
There are several aspects of the SDK that deserve some attention:-
Input Parameters: to execute every Telnyx Voice API Command you’ll need to feed your function with the following:- the
Call Control ID - the input parameters, specific to the body of the Command you’re executing.
- the
Call Control ID except Dial. There you’ll get a new one for the leg generated as response.
In this example you can see that Call Control ID is input to the Telnyx Call Object. The command to utilize is then specifed when the new Call Object is called with the input paramters pertaining to that command.
Telnyx Voice API commands
This is how every Telnyx Voice API Command used in this application looks:Voice API bridge
Voice API dial
Voice API gather using speak
Voice API speak
Voice API hangup
Voice API recording start
SMS send notification
The client state parameter
Client State: within some of the Telnyx Call Control Commands list we presented, you probably noticed we were including the Client State parameter. Client State is the key to ensure that we can perform functions only when very specific conditions are met on our App while consuming the same Call Control Events.
Because the Telnyx Voice API is stateless and async your application will be receiving several events of the same type, e.g. user just included DTMF. With Client State you enforce a unique ID to be sent back to Telnyx which be used within a particular Command flow and identifying it as being at a specific place in the call flow.
This app in particular will bridge two seperate calls together in the event the user chooses to accept the call. Thus the call_control_id of the pending bridge call must be mapped, and not be risked to being stored in a variable which could be re-assigned while we are waiting for gather response - should a new call be intiated.
Build client state object and encode to base64
Building find me follow me IVR
With all the basic Telnyx Voice API Commands set, we are ready to consume them and put them in the order that will create the IVR. For this tutorial we want to keep it simple with a flow that corresponds to the following IVR Logic:- Allow the incoming call to be parked.
- Execute dial function to the user’s PSTN number.
- Present an IVR allowing them to Accept or Reject the call and execute a 20 second timeout to hangup for no answer.
- When the user answers, they will be met with an IVR Greeting:
- Press 1 to Accept the Call - The Parked Call and this Dialed call will now be Bridged. The Timeout to Hangup the Dial call to user will be cleared.
- Press 2 to Reject the call - The Dialed Call will hang up. The Parked call will enter the Voicemail Functionality via Speak and Recording Start
- At any time during the caller, the user can press *9 to initiate on demand call recording.
- An SMS notification will be sent to the user to notify them of a call recording or voicemail message. (Optionally) - the nodemailer function will send an email to the user with a link to download and listen to the recording.
To exemplify this process we created a simple API call that will be exposed as the webhook in Mission Portal. For that we would be using express:
express we can create an API wrapper that uses HTTP GET to call our Request Token method:
g_appName in the previous point. That is part of a set of global variables we are defining with a certain set of info we know we are going to use in this app: TTS parameters, like voice and language to be used and IVR redirecting contact points.
You can set these at the beginning of your code:
APP CODE GOES HERE. So as you expose the URL created as Webhook in Mission Control associated with your number, you’ll start receiving all call events for that call.
So the first thing to be done is to identify the kind of event you just received and extract the Call Control Id and Client State (if defined previously):
Event Type and client_state received, it’s just a matter of having your application reacting to that. Is the way you react to that Event that helps you creating the IVR logic. What you would be doing is to execute Telnyx Call Control Command as a reaction to those Events.
Webhook call initiated >> Command answer call
If our event_type is call.initiated and the direction is incoming we are going to execute the command to Dial the User. After the Dial is executed and we get a new webhook for the dialed call which the direction will be “outgoing,” we will specify our timeout_secs parameter to 30 seconds so that the user’s mobile voicemail doesn’t pick up and we leave an empty message there
Webhook dial answered >> Command gather using speak
Once your app is notified by Telnyx that the call was established you want to initiate your IVR. You do that using the Telnyx Voice API Command Gather Using Speak, with the IVR message.
As part of the Gather Using Speak Command we indicate that valid digits for the DTMF collection are 1 and 2, and that only 1 digit input would be valid. Since we only want to execute this when the call is answered by the user via the dial, we set client_state to “stage-bridge” on the Dial seen above.
200 OK.
Webhook call bridged >> Do nothing
Your app will be informed that the call was bridged should the user choose to accept the call. For the APP we are doing nothing with that info, but we will need to reply to that command.
Webhook listen for DTMF to execute call recording on demand
We need to be listening for the specified digit in order to execute the recording on demand feature, specifically ***. Now this example is very rudimentary and is just for proof of concept. In production, the dtmf should only be received from the user’s call leg. Additionally here, we will empty the array once the condition is met and we execute the Recording Start Command. We are also re-using this to record are voicemail message.
call.gather.ended and call.dtmf.received. The main difference is that in the gather webhooks dtmf will be sent as value to key “digits” and in dtmf.received the key will be “digit.”
Webhook gather ended >> Find me IVR logic
It’s when you receive the Webhook informing your application that Voice API Gather Ended (DTMF input) that the IVR magic happens:
We’re doing a number of things here.
- If the user presses 1, we are first going to clear the timeout for this Dialed call so it does not hangup automatically. Second, we are going to issue “bridge” to connect the caller and the user.
- If the user presses 2, we are going to do execute two commands. We will speak the voicemail greeting to the caller, and issue hangup to the users mobile.
l_call_control_idThe call control id of the latest webhook we just recieved the DTMF on and has aclient_stateof “stage-dial”l_bridge_idThe PSTN caller’s call control id, we set that variable to our client state object inl_client_state.bridgeIdearlier when we first received the webhook on the incoming call.
client_state as we’re only executing the bridge on the dial webhook that we set client_state of “stage-dial”.
Webhook gather ended >> Process DTMF for IVR
Webhook call recording saved >> Send text message of recording
We are receiving a webhook of call.recording.saved after BOTH a voicemail has been recorded and if a record call on demand has been executed. Now in this web hook we will recieve a link to an mp3 recording of either the voicemail or recorded call. We are going to send an sms notification to the User via sms_send_notification. Optionally, we are using the nodemailer sdk to send an email to the user with the link so they can listen to the message or call.
Lightning-up the application
Finally the last piece of the puzzle is having your application listening for Telnyx Webhooks:Ruby
⏱ 30 minutes build timeIntroduction to the call control framework
The Voice API framework, previously called Call Control, is a set of APIs that allow complete control of a call flow from the moment a call begins to the moment it is completed. In between, you will receive a number of webhooks for each step of the call, allowing you to act on these events and send commands using the Telnyx Library. A subset of the operations available in the Call Control API is the Call Control Conference API. This allows the user (you) to create and manage a conference programmatically upon receiving an incoming call, or when initiating an outgoing call. The Telnyx Ruby Library is a convenient wrapper around the Telnyx REST API. It allows you to access and control call flows using an intuitive object-oriented library. This tutorial will walk you through creating a simple Sinatra server that allows you to create an IVR demo application.Setup your development environment
Before beginning, please ensure that you have the Telnyx, Dotenv, and Sinatra gems installed.Setting environment variables
The following environmental variables need to be set Variable Description TELNYX_API_KEY Your Telnyx API Key TELNYX_PUBLIC_KEY Your Telnyx Public Key TELNYX_APP_PORT Defaults to 8000 The port the app will be served.env file
This app uses the excellent dotenv package to manage environment variables. Make a copy of the file below, add your credentials, and save as.env in the root directory.
Portal setup
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using Voice API. The Voice API Application needs to be setup to send API V2 webhooks:- Make sure the Webhook API Version is API v2.
- Fill in the Webhook URL with the address the server will be running on. Alternatively, you can use a service like Ngrok to temporarily forward a local port to the internet to a random address and use that. We’ll talk about this in more detail later.
ivr_demo_server.rb, then write the following to setup the Telnyx library.
Receiving webhooks & answering a call
Now that you have setup your auth token andcall_control_id, you can begin to use the API Library to answer a call and receive input from DTMF. First, you will need to setup a Sinatra endpoint to receive webhooks for call and DTMF events. There are a number of webhooks that you should anticipate receiving during the lifecycle of each call. This will allow you to take action in response to any number of events triggered during a call. In this example, you will use the call.initiated and call.answered events to answer the incoming call and then present IVR options to the user. You’ll use the call.gather.ended event to parse the digits pressed during the IVR.
.env file and create an endpoint at /webhook, which can be anything you choose as the API doesn’t care; here we just call it webhook.
call object from the call_control_id nested in the webhook.data.payload JSON. This will allow you to send commands to the active call.
Telnyx::Call object and store it in the active call list, then call call.answer to answer it if it’s an inbound call.
call.answered event, we can call the gather_using_speak command to speak audio and gather DTMF information from the user input.
Take note that the valid_digits restricts the input to the caller to only the digits specified. The invalid_payload will be played back to the caller before the payload is repeated back if any invalid digits are pressed when the gather completes.
valid, invalid, call_hangup, cancelled, cancelled_amd), the call.gather.ended event is sent to the webhook endpoint. From there, we can extract the digits field from the payload and play it back to the user using speak.
Take note that the call_hangup status indicates the caller hungup before the gather could complete. For that case, we’re done as speak does not work on an ended call.
Authentication for your calls
Now you have a working conference application! How secure is it though? Could a third party simply craft fake webhooks to manipulate the call flow logic of your application? Telnyx has you covered with a powerful signature verification system! Make the following changes:.env file. Look up your public key from the Telnyx Portal here. Telnyx::Webhook::Signature.verify will do the work of verifying the authenticity of the message, and raise SignatureVerificationError if the signature does not match the payload.
Final ivr_demo_server.rb
All together, your ivr_demo_server.rb file should resemble something like:
Voice API Usage
If you used a Gemfile, start the conference server withbundle exec ruby ivr_demo_server.rb, if you are using globally installed gems use ruby ivr_demo_server.rb.
When you are able to run the server locally, the final step involves making your application accessible from the internet. So far, we’ve set up a local web server. This is typically not accessible from the public internet, making testing inbound requests to web applications difficult.
The best workaround is a tunneling service. They come with client software that runs on your computer and opens an outgoing permanent connection to a publicly available server in a data center. Then, they assign a public URL (typically on a random or custom subdomain) on that server to your account. The public server acts as a proxy that accepts incoming connections to your URL, forwards (tunnels) them through the already established connection and sends them to the local web server as if they originated from the same machine. The most popular tunneling tool is ngrok. Check out the ngrok setup walkthrough to set it up on your computer and start receiving webhooks from inbound messages to your newly created application.
Once you’ve set up ngrok or another tunneling service you can add the public proxy URL to your Connection in the MIssion Control Portal. To do this, click the edit symbol [✎] next to your Connection. In the “Webhook URL” field, paste the forwarding address from ngrok into the Webhook URL field. Add /webhook to the end of the URL to direct the request to the webhook endpoint in your Sinatra server.
Callback URLs for Telnyx applications
Callback Type URL Inbound Calls Callback{ngrok-url}/webhook
For now you’ll leave “Failover URL” blank, but if you’d like to have Telnyx resend the webhook in the case where sending to the Webhook URL fails, you can specify an alternate address in this field.
Complete running Voice API IVR application
You have now created a simple IVR application! Using other Call Commands, you can perform actions based on user input collected during a gather. For more information on what call commands you can use, check out the Call Command DocumentationsCall Center
Source: https://developers.telnyx.com/docs/voice/programmable-voice/call-center.md⏱ 30 minutes build time. 🧰 Clone the sample application from our GitHub repo. 🎬 Check out our video walkthrough of this tutorial.
Introduction
In this tutorial, you’ll learn how to build a call center application using the Telnyx Voice API, TeXML, and the Python AIOHTTP library, in three main parts:- Set up and configure your Mission Control Portal to link a call center number to your call center agents’ TeXML-enabled SIP connections.
- Set up and run the sample call center application in your preferred environment.
- Optional: Configure your call center app with customized audio playback, hangup messages, and voicemail storage.
All of these steps in the call flow can be modified, configured, or built upon by editing TeXML files in the
- A user calls the main phone number associated with the call center, and the call is answered with a text-to-speech greeting.
- The call is forwarded to multiple agents simultaneously, with call recording enabled.
- If one of the agents answers the call, the other agents stop ringing.
- If no agent answers the call, a second text-to-speech message is played, and the agents are dialed for a second time.
- If no agent answers on the second dialing attempt, the user may leave a voicemail recording.
- If the call is answered and subsequently ended, a text-to-speech message will thank the user for calling.
/call_center/infrastructure/TeXML directory of the repo.
Jump to section:
- Creating a Telnyx Mission Control Portal account
- Creating a Telnyx API key
- Installing ngrok
- Creating a TeXML Application
- Buying a phone number
- Creating your agents’ SIP Connections
- Creating an Outbound Voice Profile to associate with agents’ SIP Connections
- Setting up your virtual environment
- Running application setup and configuring variables
- Running the application
- Optional: Configuring your hangup behavior with TeXML
- Optional: Configuring custom audio playback
- Optional: Configuring voicemail recording and storage
Configuring the Mission Control Portal
Step 1: Create a Telnyx mission control portal account
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using Call Control.Step 2: Create a Telnyx API key
API keys allow your application to access the telephony resources associated with your Telnyx account. In this example, your API key allows the locally-running call center app to access numbers, SIP connections, outbound voice profiles, and TeXML applications that you’ll create in the Mission Control Portal during this tutorial. Learn more about using Telnyx API keys for authentication.Keys can be created in the API Keys section of the portal.
Step 3: Install and run ngrok
In this example, ngrok is used to receive webhooks sent from the TeXML application to your locally running call center application via a tunneling URL to a port on your machine. These webhooks inform the local application about events like incoming and answered calls. Learn more about using ngrok with Telnyx.Download and install ngrok following the developer’s instructions from https://ngrok.com/download. Start up ngrok by running
./ngrok http 8080 and make note of the HTTPS Forwarding URL.
Step 4: Create a TeXML application
TeXML is the quickest way to build programmable voice applications in minutes using a simple XML data structure. Learn more about TeXML in our tutorial.Add a new TeXML Application in the Call Control section of the Mission Control Portal, selecting Add a new TeXML Application in the top navigation menu. Set the Voice Method to
GET and specify your webhook URL as your_ngrok_forwarding_url/TeXML/inbound - e.g. https://b06b087392cd.ngrok.io/TeXML/inbound
Set the Status Callback Method to POST and specify your callback URL as your_ngrok_forwarding_url/TeXML/events - e.g. https://b06b087392cd.ngrok.io/TeXML/events
Step 5: Buy a phone number
Use the Search & Buy Numbers tool in the Mission Control Portal to find a voice-enabled phone number and add it to your cart. At checkout, use the drop-down box labeled Connection or Application to select the TeXML application you just created. This associates your new phone number with the application. This is your call center phone number that users will call to reach your organization.
Step 6: Create your agents’ Credentials-based SIP Connections
Add a new SIP Connection from the SIP Connections section of the Mission Control Portal. Select Credentials as the SIP Connection Type. It’s good practice to set the username to be something unique and representative of the agent who will be assigned to the connection. Your connections need to send webhooks to inform your TeXML application about the status of calls so that the application will stop trying to dial other connections when one connection answers an incoming call. Under Events, specify the Webhook URL asyour_ngrok_forwarding_url/outbound/event.
Hit Save & Finish Editing to save your progress.
When a user calls your call center number, the TeXML application forwards the call to each of the SIP connections associated with the application. Because all of the connections we’re creating use SIP URIs instead of phone numbers, these connections need to be able to receive SIP URI calls.
Find the connection you just created in the connections list and open the Inbound Options menu. In the Inbound section, set Recieve SIP URI Calls to From anyone.
Lastly, if your agents will be making outbound calls, you may want to enable a caller ID override, which enables Telnyx to send a specified caller ID for each agent. This setting can be found under the Outbound section of the SIP Connection Options menu.
Repeat this step to create a new connection for each agent you wish to connect to the call center.
Telnyx is fully compatible with every major free softphone platform, with in-depth configuration guides for each one.
Don’t have a SIP desk phone or softphone to use with this demo? Why not try WebRTC? Load up our free WebRTC development demo tool and enter your SIP connection credentials to start making and receiving calls directly from your browser.
Step 7: Create an Outbound Voice Profile and associate all the SIP Connections
Outbound calls must be enabled for the TeXML Application to forward incoming calls to your agents’ SIP Connections. Outbound calls are configured with an Outbound Voice Profile, which is in turn associated with each SIP Connection to enable calls to be forwarded to that connection. Add a new profile from the Outbound Voice Profiles section of the portal, then hit Add connections/apps to profile and select each of the connections you created in the previous step. Outbound Voice Profiles allow outbound calls to be placed within the United States and Canada by default. You can enable outbound calling to international destinations in the International Allowed Destinations menu when configuring an Outbound Voice Profile.Configuring your environment and running the application
Step 8: Set up virtual your virtual environment
The sample application requires Python version 3.6 or higher and leverages theaiohttp, apscheduler, and python-dotenv packages. You can install these packages manually using pip, or use a packaging tool like pipenv to install them automatically inside a virtual environment.
To install pipenv, run:
pipenv to install the required packages, navigate to the /call-center-texml directory, and run:
Step 9: Set up and configure variables
The sample application interfaces with the Telnyx resources set up via the Mission Control portal by passing a set of environment variables, including your API key and other unique identifiers, into the app. Setting up the app involves running a setup script that creates a .env file, into which you can populate these environment variables. In the/call-center-texml directory, run:
.env file within the /call-center-texml/call-center directory. Open this .env file and fill in the required variables:
API_KEY: This is your Telnyx API Key, created in Step 2.PROD: Defaults to True. You can set this to either True or False. If set to True, scheduled jobs for updating connections and sending account balance notifications will run at automated time intervals.SLACK_URL: If you wish to integrate your call center with Slack to receive live notifications for incoming calls, this URL will be configured for incoming webhooks in the Slack app. More on setting up Slack API integrations can be found in Slack’s documentation.- Note: The
SLACK_URLcan be left blank if Slack is not being used.
- Note: The
NGROK_URL: This is the Forwarding URL from Step 3.OUTBOUND_PROFILE_ID: This is the ID of the Outbound Voice Profile from Step 7. The ID can be found and copied by opening the configuration settings of the profile.
Step 10: Running The Application
From the/call-center-texml directory, run the following command to start the application:
Optional: Customizing your call center app
Configure your hangup behavior
When a call is answered and subsequently ended by an agent, the customer hears a text-to-speech message thanking them for calling. Like any other behavior in the call flow, this behavior can be configured by modifying the relevant TeXML files. This particular behavior is specified in the answered.xml file, located in the/call_center/infrastructure/TeXML/ directory. The default behavior uses a ](/docs/voice/programmable-voice/texml-verbs/say) verb in this file to speak a text string. If you have an IVR, you may instead wish to use a [ or “ verb, which could send the caller to another line or back to the IVR, should they wish to have a conversation with another department.
Play custom audio files
The TeXML files are configured to use text-to-speech by default, using “ verbs to communicate information to the user. However, the application is also capable of delivering audio files for initial greetings and hold messages, using the “ verb. All you need to do is record the audio and place the resultant files in a new subdirectory under/call_center/infrastructure/audio, named:
support_greeting.mp3support_busy.mp3
verbs that are in the `busy_template.xml` and `inbound_template.xml` files, and remove or comment-out the verbs to prevent the file from reading text-to-speech directly after playing your audio file:
There’s no need to change the {ngrok_url} placeholder in the above example - this is populated at runtime from the environment variables you set up in Step 9.
Configure voicemail recording and storage
You can also specify a recording status callback URL in thevoicemail.xml file. When a call ends after being sent to voicemail, the TeXML application sends a POST request with the URL of the recording file to the status callback URL you specified.
Where to Next?
Now that you’ve set up a fully-functioning, deeply customizable call center application using TeXML, the possibilities are endless:- Read the story of how we built a bespoke call center for our 24/7 technical support team using TeXML, in our two-part blog series.
- Check out the full TeXML documentation for a list of commands that can be used in your XML files.
- Check out a video walkthrough of this tutorial.
- Learn more about Telnyx for Contact Centers .
Call Tracking
Source: https://developers.telnyx.com/docs/voice/programmable-voice/call-tracking.md| Python | Node |
Python
⏱ 60 minutes build time. 🧰 Clone the sample application from our GitHub repo In this tutorial, you’ll learn how to build a Call Tracking application using the Telnyx API, and our Python SDK. Call Control (the Telnyx Voice API), combined with our Numbers API, provides everything you need to build a robust number ordering and call tracking application:- The Numbers API enables you to search the Telnyx phone number inventory in real time; filtering by Area Code, City/State, and more to find the perfect local number for your use-case.
- Call Control enables you to quickly setup dynamic forwarding numbers, toggle dual-channel recording, join/leave dynamic conferences, and pull post-call analytics.
- Search and order phone numbers by a city and state combination.
- Receive inbound calls to the Telnyx phone number.
- Transfer calls using Call Control to your designated Forwarding Number.
- Store all required information in a database of your choice.
- Make a front-end that shows what’s going on.
Create a Telnyx mission control portal account
To get started, you’ll need to create an account. Verify your email address and you can log into the Mission Control Portal to get started.Set up your local machine to receive webhooks from Telnyx
Next, you’ll need a means of receiving webhooks sent by Telnyx to notify your application of call events. One of the easiest ways to accomplish this is to use a tool like ngrok to generate a tunnelling URL, which connects to a locally running application via a port on your machine. In this example, port8000 is used. After downloading and installing ngrok, run ./ngrok http 8000 and make note of the resultant HTTPS Forwarding URL.
Create a Telnyx call control application
From the Portal, create a new Call Control Application , and paste the HTTPS Forwarding URL from the previous steps to send webhooks from this application to your local machine via ngrok. Ensure API v2 is selected, and save your application. We don’t need to worry about any other application settings for now. Select your application again to edit it, and make a note of the ID. This is how you’ll identify your Call Control Application in your code.Create an Outbound Voice profile
From the Portal, create a new Outbound Voice Profile. Click Add connections/apps to profile and select the Call Control Application you created in the previous step. In the International Allowed Destinations section, ensure you have selected the region(s) in which you want your application to work.Initialize and install packages via pip
Initialize your call tracking application with the defaults presented to you and create a virtual environment.Set up environment variables
The following environment variables need to be set for your call tracking application to work: Variable Description TELNYX_API_KEY Your Telnyx API Key, which can be created in the portal. TELNYX_PUBLIC_KEY Your Telnyx Public Key, which is accessible via the portal. TELNYX_CONNECTION_ID The ID from your Call Control Application MESSAGING_PROFILE_ID The ID from your Messaging Profile DATABASE_HOST Connection of the host (ie. localhost or your local ip address) DATABASE_USER Your database user name DATABASE_PASSWORD Your database password DATABASE_NAME Your database name DATABASE_PORT Your database port This app uses the excellent dotenv package to manage environment variables. Make a copy of the file below, add your credentials, and save as.env in the root directory.
Create some folders and Python files to build our call tracking application
We’ll use a few.py files to build the call tracking application.
app.pyas our entry point to the applicationdatabase.pyfor our databasedatabase_queries.pyfor our database controllertelnyx_commands.pyto manage most of our telnyx related functions
modelto host our databse related quieriesstaticfor our css and jstemplatesas our entry point to everything html and frontend that we would want
Setup basic Telnyx commands
Here we will setup some basic commands to get ourselves going for the call tracking app. We will want the ability to procure some numbers via the API, have the capability to delete them, and look up some basic CNAM paramaters if we can. As such, we will be creating some basic functions:-
telnyx_number_acquire(locality, administrative_area): This will handle the number search and ordering portion of our app when given the specific arameters
- We will be specifying locality and rate_center which corresponds with City and State.
- We will also go ahead and search for numbers that are SMS capable so we can future proof just in case we would want to be adding on an SMS component to this.
- Setting limit as 1 to fetch and procure the first result
- Making sure quickship is set as True, so we get numbers that are actively ready to go out of the box and will not have to wait for procurement.
- We will want to return the
number_to_orderandcity_state_comboto pass which number and from where exactly we procured this from
- telnyx_number_delete(number_to_delete): This will handle deleting phone numbers in our portal
-
telnyx_cnam_lookup(calling_number): This will handle using Telnyx Lookup service to see if we can get information on the number that’s calling us
- We will be returning the variable
cnam_infowith the result to use later on
- We will be returning the variable
-
difference(start_time, end_time): This handles conversion of the webhook start/end times to get call durations
- Webhook times are in full time format, so we will use the included datetime function to convert the time into seconds before doing the math to get the difference for the duration
- We will be returning both
durationanddate
Database and database queries setup
We will need to now setup our database and store some of this data that we will be getting. You can setup a basic database in-memory, but obviously this results with the drawback of it being killed every time the app is restarted. As such, I’ve personally chosen to use Oracle SQL. I believe a relational database makes the most sense in this case to use, as we are relating tracking inbound numbers that are calling us with forwarded phone numbers. ie. all the data that would be presented is tied to the same call/number combination. So for this we will be creating two files:-
database.py: to setup and create our basic database -
database_queries.py: to provide all the functions we would need related to our database
in database.py
- We will be using peewee to connect to our database
- We will then define our table classes and add a function to create them at the end
database.py (if you were to pass the correct dot.env variables related to database login), you should successfully be able to create the tables in your desired database.
For MySQL, do make sure your database schema is created first and matches your DATABASE_NAME parameter, for example in MySQL Workbench
Setup Flask Server for Number Ordering and Call Tracking
Theapp.py file sets up 5 routes:
/: Our base route, where we will have our interface once we construct our index.html/number: To manage our number ordering and patching that we will be setting up/call: This path will relate to our call logging service that we will show. We will need to hit this if we would like to delete certain calls/call-control/inbound: This points to our main call-control processing/call-control/outbound: To manage our number ordering and patching that we will be setting up
/call-control/inbound route.
Here we are performing the function of parsing through the incoming webhooks that we will be getting into our application, specifically:
- Receiving inbound call webhooks
- Answering the inbound call
- Transferring the call to the destination number saved in the database
- Saving the hangup event to the database
Building the front-end
The front-end was built with Boostrap and Nunjucks. I won’t go into much detail about building it out in this article, but if you want to attach your methods from above simply import the resources located in the static and templates folders located on our GitHub page.Running the call tracking application
We should now be able to run the application!Launch ngrok and update your call control application
We need to be able to receive webhooks from Telnyx, sent over the public Internet. We’ll use ngrok for this tutorial. Launch ngrok on thePORT specified in your .env file. If you’re using port 8000 (the default for this app), you can simply run ./ngrok http 8000
/call-control/inbound to the end of the URL to direct the request to the webhook endpoint in your server.
If we were using the example URL from the code sample above, the URL would be http://ead8b6b4.ngrok.io/call-control/inbound.
Run the APP.PY Call tracking application
Start the server by runningpython app.py.
Once everything is setup, you should now be able to:
- Search and purchase a number based on your parameters
- Allocate the purchased number to your desired forwarding number
- Track your acquired forwarded phone numbers in your database
- Record and store call information relating to those numbers in your database
- Present all of this information in your UI
Call tracking follow-ons
Now that you’ve successfully constructed this application, you have the freedom to expand it as you wish! You can start saving even more information from the webhooks such as IDs in your database by adding more tables, you can add more routes to handle inbound messaging functions, you can add recording/auto answer functions… it’s all up to you! Our developer Slack community is full of Python developers like you - be sure to join to see what your fellow developers are building!Node
⏱ 60 minutes build time. 🧰 Clone the sample application from ourGitHub repo In this tutorial, you’ll learn how to build a Call Tracking application using the Telnyx API, and our Node SDK. Programmable Voice, combined with our Numbers API, provides everything you need to build a robust call tracking application:- The Numbers API enables you to search the Telnyx phone number inventory in real time; filtering by Area Code, City/State, and more to find the perfect local number for your use-case.
- Call Control enables you to quickly setup dynamic forwarding numbers, toggle dual-channel recording, join/leave dynamic conferences, and pull post-call analytics.
- Search and order a phone number by area code.
- Store a ‘binding’ of Telnyx phone numbers to a forwarding number (to which incoming calls to the Telnyx phone numbers will be forwarded).
- Receive inbound calls to the Telnyx phone number.
- Transfer calls using Call Control.
- Store webhook events associated with calls to a datastore.
Create a Telnyx mission control portal account
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using Call Control.Set up your local machine to receive webhooks from Telnyx
One of the easiest ways to accomplish this is to use at tool like ngrok to generate a tunnelling URL, which connects to a locally running application via a port on your machine. In this example, port8000 is used. After downloading and installing ngrok, run ./ngrok http 8000 and make note of the resultant HTTPS Forwarding URL.
Create a Telnyx call control application
From the Portal, create a new Call Control Application , and paste the HTTPS Forwarding URL from the previous steps to send webhooks from this application to your local machine via ngrok. Ensure API v2 is selected, and save your application. We don’t need to worry about any other appliction settings for now. Select your application again to edit it, and make a note of the ID. This is how you’ll identify your Call Control Application in your code.Create an outbound voice profile
From the Portal, create a new Outbound Voice Profile. Click Add connections/apps to profile and select the Call Control Application you created in the previous step. In the International Allowed Destinations section, ensure you have selected the region(s) in which you want your application to work.Initialize and Install packages via npm
Initialize your call tracking application with the defaults presented to you.package.json file with the packages needed to run the application.
Set up environment variables
The following environment variables need to be set for your call tracking application to work: Variable Description TELNYX_API_KEY Your Telnyx API Key, which can be created in the portal. TELNYX_PUBLIC_KEY Your Telnyx Public Key, which is accessible via the portal. TELNYX_CONNECTION_ID The ID from your Call Control Application PORT The port through which the app will be served. This variable defaults to 8000 This app uses the excellent dotenv package to manage environment variables. Make a copy of the file below, add your credentials, and save as.env in the root directory.
Create JavaScript files to build a Call Tracking Application
We’ll use a few.js files to build the call tracking application.
index.jsas our entry point to the applicationdb.jsfor our database controller (in-memory DB for sample)callControl.jsto manage call-control webhooksbindings.jsto manage call-tracking bindings and post-call metadata
Setup Express Server for Call Tracking
Theindex.js file sets up 2 express routes:
/call-control: To handle call-control webhooks/bindings: To manage phone number bindings and call information
Setup database for Call Tracking information
Thedb.js file contains the in-memory database to manage our phone numbers and call information. It exports 1 array and 3 functions:
bindings = []: Our in-memory databaseaddPhoneNumberBinding: accepts a Telnyx phone number and a destination number to save to the database.- Called when ordering / creating a new call-tracking number
getDestinationPhoneNumber: accepts a Telnyx phone number and searches the database for a match, then returns the destination phone number.- Called when receiving an inbound call to look up transfer destination.
saveCall: accepts a Telnyx event and saves the call to the database based on the payload.- Called when the
call.hangupevent is received to save post-call information
- Called when the
getBinding: accepts a Telnyx phone number and returns the matching binding information from the database.- Called when
GETbindings has a telnyxPhoneNumber query parameter
- Called when
Managing phone number bindings for Call Tracking
Thebindings.js file contains all the logic for:
- Searching Phone Numbers by area code (also known as
national_destination_code) - Ordering Phone Numbers and setting the
connection_idas part of the order - Saving the binding to the database
- Routes for fetching binding information
Managing call flows for call tracking
ThecallControl.js file contains the routes and functions for:
- Receiving inbound call webhooks
- Answering the inbound call
- Transferring the call to the destination number saved in the database
- Saving the hangup event to the database
Running the Call Tracking application
Now that you’ve saved all the examples and built your routes, it’s time to run the application.Launch ngrok and update your Call Control Application
We need to be able to receive webhooks from Telnyx, sent over the public Internet. We’ll use ngrok for this tutorial. Launch ngrok on thePORT specified in your .env file. If you’re using port 8000 (the default for this app), you can simply run ./ngrok http 8000
/call-control/inbound to the end of the URL to direct the request to the webhook endpoint in your server.
If we were using the example URL from the code sample above, the URL would be http://ead8b6b4.ngrok.io/call-control/inbound.
Run the Node.JS call tracking application
Start the server by runningnode index.js.
Once everything is setup, you should now be able to:
- Allocate a new call tracking number and bind it to a forwarding number
- Call the allocated number and get connected to the destination.
Create a binding for call tracking
The bindings interface is managed through a RESTful API. To create a new binding create aPOST request to your ngrok URL (in this example: http://ead8b6b4.ngrok.io/bindings)
The POST request accepts a JSON object with the following fields:
areaCode: Desired area code for the new call tracking phone numberdestinationPhoneNumber: Number which we’ll forward all incoming calls to the call-tracking phone number
areaCode passed, and will order the first result returned from the API. It then creates a binding so that any inbound call to the Telnyx phone number is forwarded to the destination phone number.
List call tracking bindings and call information
The bindings endpoint supports aGET request to pull call information and existing bindings.
The bindings object returns a calls array with the hangup webhooks saved. The length of the array equals the number of calls the call tracking number received. The duration for each call can be calculated as the difference between the start_time and end_time values.
Call tracking follow-Ons
Now that you’ve successfully built a call tracking application, you can explore more features and discover ideas to build new applications. Our developer Slack community is full of Node developers like you - be sure to join to see what your fellow developers are building!Conferencing
Source: https://developers.telnyx.com/docs/voice/programmable-voice/conferencing-demo.md| Python | PHP | Node | Ruby |
Python
⏱ 60 minutes build time || Github RepoIntroduction
The Voice API framework, previously called Call Control, is a set of APIs that allow complete control of a call flow from the moment a call begins to the moment it is completed. In between, you will receive a number of webhooks for each step of the call, allowing you to act on these events and send commands using the Telnyx Library. A subset of the operations available in the Voice API is the Conference API. This allows the user (you) to create and manage a conference programmatically upon receiving an incoming call, or when initiating an outgoing call. The Telnyx Python Library is a convenient wrapper around the Telnyx REST API. It allows you to access and control call flows using an intuitive object-oriented library. This tutorial will walk you through creating a simple Flask and Ngrok server application that allows you to create and manage a conference.Setup
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API.- make sure the Webhook API Version is API v2
python installed to continue. You can check this by running the following:
telnyx, so make sure you have it installed. If not you can install it with the following command:
Server and Webhook setup
Flask is a great application for setting up local servers. However, in order to make our code public to be able to receive webhooks from Telnyx, we are going to need to use a tool called ngrok. Installation instructions can be found here. Now to begin our flask application, underneath the import and setup lines detailed above, we will add the following:Receiving and interpreting Webhooks
We will be configuring our respond function to handle certain incoming webhooks and execute Voice API commands based on what the values are. Flask catches the incoming webhooks and calls the respond() function every time a webhook is sent to the route we specified as ‘/webhook’. We can see the json value of the hook in the request.json object. Here is what a basic Telnyx Call Object looks likeReceiving Webhooks & creating a conference
Below is the logic that will go inside our respond() function. When we receive a webhook, we extract the data fromrequest.json.get('data') and we look at the event_type inside that object to determine a course of action.
record_type is event. Then, we extract the event_type itself and use logic to determine the action taken based on the event.
call_control_id and call_leg_id from the incoming data. We then use telnyx.Call.answer(new_call) to answer the call. This will trigger a webhook event call.answered which we will handle below.
call.answered event, retrieve the stored call created during the call.initiated event. Then, either create a new conference if this is the first call and there isn’t a conference running yet, or add the call to an existing conference. Note that a call_control_id is required to start a conference, so there must aready be an existing call before you can create a conference, which is why we create the conference here.
Conclusion
The full tutorial with comments can be found on Github.PHP
⏱ 60 minutes build time || Github RepoIntroduction
The Voice API framework, previously called Call Control, is a set of APIs that allow complete control of a call flow from the moment a call begins to the moment it is completed. In between, you will receive a number of webhooks for each step of the call, allowing you to act on these events and send commands using the Telnyx Library. A subset of the operations available in the Telnyx Voice API is the Conference API. This allows the user (you) to create and manage a conference programmatically upon receiving an incoming call, or when initiating an outgoing call. The Telnyx PHP Library is a convenient wrapper around the Telnyx REST API. It allows you to access and control call flows using an intuitive object-oriented library. This tutorial will walk you through creating a simple Slim server that allows you to create and manage a conference.What can you do
At the end of this tutorial you’ll have an application that:- Verifies inbound webhooks are indeed from Telnyx
- Creates a conference for the first caller
- Adds additional callers to the existing conference
- Tears down the conference when the last call leaves
- Will create a new conference when the next caller dials in
Setup
Before beginning, please setup ensure that you have composer installed.Install packages
composer.json file with the packages needed to run the application.
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API.
The Voice API Application
needs to be setup to work with the conference control api:
- make sure the Webhook API Version is API v2
- Fill in the Webhook URL with the address the server will be running on. Alternatively, you can use a service like ngrok to temporarily forward a local port to the internet to a random address and use that. We’ll talk about this in more detail later.
Setting environment variables
This tutorial uses the excellent phpenv package to manage environment variables. Create a.env file in your root directory to contain your API & Public key. BE CAREFUL TO NOT SHARE YOUR KEYS WITH ANYONE Recommended to add .env to your .gitignore file.
Your .env file should look something like:
Code-along
Now create a folderpublic and a file in the public folderindex.php, then write the following to setup the telnyx library.
Setup slim server and instantiate Telnyx
$CONFERENCE_FILE_NAME = '../conference_id.txt'; will be used to track conference state.
Receiving Webhooks & creating a conference
Now that you have setup your auth token, phone number, and connection, you can begin to use the API Library to make and control conferences. First, you will need to setup a Slim endpoint to receive webhooks for call and conference events. There are a number of webhooks that you should anticipate receiving during the lifecycle of each call and conference. This will allow you to take action in response to any number of events triggered during a call. In this example, you will use thecall.initiated, call.answered, and conference.ended events to add calls to a conference and tear it down. Because you will need to wait until there is a running call before you can create a conference, plan to use call events to create the conference after a call is initiated.
Basic routing & functions
The basic overview of the application is as follows:- Verify webhook & create TelnyxEvent
- Check event-type and route to the event handler
call.initiatedevents are answeredcall.answeredevents check if there is a conference, if so; join, if not, create new conferenceconference.endedwill tear down the existing conference making way for a new one.
Webhook validation middleware
Telnyx signs each webhook that can be validated by checking the signature with your public key. This example adds the verification step as middleware to be included on all Telnyx endpoints.Conference management
For each call, we need to check if there is already a conference. In a more sophisticated application this would typically be solved by a connection to any given data store. For this demo, we’re managing the state in a file on disc$CONFERENCE_FILE_NAME.
Event Handlers and switch
For each event (besidescall.initiated we need to check the current state of the conference before making next steps)
Usage
Start the serverphp -S localhost:8000 -t public
When you are able to run the server locally, the final step involves making your application accessible from the internet. So far, we’ve set up a local web server. This is typically not accessible from the public internet, making testing inbound requests to web applications difficult.
The best workaround is a tunneling service. They come with client software that runs on your computer and opens an outgoing permanent connection to a publicly available server in a data center. Then, they assign a public URL (typically on a random or custom subdomain) on that server to your account. The public server acts as a proxy that accepts incoming connections to your URL, forwards (tunnels) them through the already established connection and sends them to the local web server as if they originated from the same machine. The most popular tunneling tool is ngrok. Check out the ngrok setup walkthrough to set it up on your computer and start receiving webhooks from inbound messages to your newly created application.
Once you’ve set up ngrok or another tunneling service you can add the public proxy URL to your Connection in the Mission Control Portal. To do this, click the edit symbol [✎] next to your Connection. In the “Webhook URL” field, paste the forwarding address from ngrok into the Webhook URL field. Add /Callbacks/Voice/Inbound to the end of the URL to direct the request to the webhook endpoint in your slim-php server.
For now you’ll leave “Failover URL” blank, but if you’d like to have Telnyx resend the webhook in the case where sending to the Webhook URL fails, you can specify an alternate address in this field.
Complete Running Voice API Conference Application
The Github Repo contains an extended version of the tutorial code above ready to run.Node
⏱ 60 minutes build time || Github Repo Telnyx Conference System demo built on Voice API V2 and node.js. In this tutorial, you’ll learn how to:- Set up your development environment to use Telnyx Voice API using Node.
- Build a simple Telnyx Voice API Conference System using Node.
- Prerequisites
- Telnyx Voice API Basics
- Building a Conference System
- Interacting with the Conference Room
- Lightning-Up the Application
Prerequisites
This tutorial assumes you’ve already set up your developer account and environment and you know how to send commands and receive webhooks using the Telnyx Voice API. You’ll also need to havenode installed to continue. You can check this by running the following:
Get started with Telnyx Voice API
For the Voice API application you’ll need to get a set of basic functions to perform Telnyx Voice API Commands plus Telnyx Voice API Conference specifics. This tutorial will be using the following subset of basic Telnyx Voice API Commands: Plus all the Telnyx Voice API Conference Commands:- Voice API Join Conference
- Voice API Mute Conference Participant
- Voice API Unmute Conference Participant
- Voice API Hold Conference Participant
- Voice API Unhold Conference Participant
HTTP POST Request to back to Telnyx server. To execute this API we are using superagent, so make sure you have it installed. If not you can install it with the following command:
Auth tab you select Auth V2. There you’ll find credentials for Auth v2 API Keys. Click on Create API Key and save the key that is shown to you. Please store it as you wont be able to fetch it later.
Once you have it, you can include it on the telnyx-account-v2.json file.
Once all dependencies are set, we can create a function for each Telnyx Voice API Command. All Commands will follow the same syntax:
Understanding the Command Syntax
There are several aspects of this function that deserve some attention:-
Function Input Parameters: to execute every Telnyx Voice API Command you’ll need to feed your function with the following:- the
Call Control ID - the input parameters, specific to the body of the Command you’re executing.
- the
Call Control ID except Dial. There you’ll get a new one for the leg generated as response.
Name of the Call Control Command: as detailed here, the Command name is part of the API URL. In our code we call that theactionname, and will feed the POST Request URL later:
Building the Telnyx Call Control Command: once you have the Command name defined, you should have all the necessary info to build the complete Telnyx Voice API Command:
Calling the Telnyx Call Control Command: Having the requestheadersandoptions/bodyset, the only thing left is to execute thePOST Requestto run the command. For that we are making use of node’srequestmodule:
Telnyx Voice API basic set
This is how every Telnyx Voice API Command used in this application looks:Voice API answer
Voice API hangup
Voice API dial
Voice API speak
Voice API recording start
Voice API recording stop
Telnyx Voice API Conference Commands
This is what every Telnyx Voice API Conference Commands look like:Conference: create conference
Conference: Join conference
Conference: Mute participant
Conference: Unmute participant
Conference: Hold participant
Conference: Unhold participant
Client State: within some of the Telnyx Voice API Commands list we presented, you probably noticed we were including the Client State parameter. Client State is the key to ensure that we can have several levels on our IVR while consuming the same Voice API Events.
Because Voice API is stateless and async, your application will be receiving several events of the same type, e.g. user just included DTMF. With Client State you enforce a unique ID to be sent back to Telnyx which can be used within a particular Command flow, identifying it as being at Level 2 of a certain IVR for example.
Building a conference system
With all the basic and conference related Telnyx Voice API Commands set, we are ready to put them in the order that will create a simple Conference System. For that all we are going to do is to:- handle incoming calls and place participants in the conference
- push for outgoing calls and place participants in the conference
- maintain a participant list
- greet the new participants before place them on the conference room
- put the first participant automatically on hold
- put a participant on-hold every-time he’s the only participant on the conference room
- un-hold the unique participant on the conference room when the second arrives
- allow remote commands to list participants, force hold/unhold, force mute/unmute, force participant push
express:
express we can create an API wrapper that uses HTTP POST to call our Request Token method:
g_appName in the previous point. That is part of a set of global variables we are defining with a certain set of info we know we are going to use in this app: TTS parameters, like voice and language to be used, etc…
For the purpose of maintaining the Conference list and state of the Conference room we also define a set of global variables.
You can set these at the beginning of your code:
If you would like to run the application on your local machine you will have to expose the app to the public internet. To do this you can useWith that set, we can fill in that space that we named asngrok. You can follow the setup guide forngrokhere.
APP CODE GOES HERE. When your webhook URL is ready you can add the webhook URL to your Mission Control Portal Connection associated with your number. Here’s an example of what a Voice API setup looks like:

Call Control Id and Client State:
Event Type received, it’s just a matter of having your application reacting to that. Is the way you react to that Event that helps you creating the IVR logic. What you would be doing is to execute Telnyx Voice API Command as a reaction to those Events.
For consistency, the Telnyx Voice API engine requires every single Webhook to be replied to by the Webhook end-point, otherwise we will keep trying to send it. For that reason, we have to be ready to consume every Webhook we expect to receive and reply with 200 OK.
Webhook call initiated >> Command answer call
Webhook call answered >> Start conference
Once your app is notified by Telnyx that the call was established you want to either start the conference room or put the participant in an already existing room.
Conference created >> Just log
Your app will be informed that the Conference was created.
Conference join >> Hold/Unhold participant
Your app will be informed that a participant just joined the room.
Conference Leave >> Remove Participant / Cleanup Vars
Your app will be informed that a participant just left the room, we need to cleanup some things.
Anything Else >> Just Ack/200ok
Interacting with the conference room
As part of the process of building a Conference Room, there is also the possibility of interacting with the application to list participants and engage with direct participants. We do that by creating a couple ofHTTP GET commands that can be then called by a browser, cURL or Postman.
Listing participants
https://:8081/telnyx-conf-v2/list
Mute participant
https://:8081/telnyx-conf-v2/mute?participant=x
Unmute participant
https://:8081/telnyx-conf-v2/unmute?participant=x
Hold participant
https://:8081/telnyx-conf-v2/hold?participant=x
Unhold participant
https://:8081/telnyx-conf-v2/unhold?participant=x
Pull participant
https://:8081/telnyx-conf-v2/pull?number=x
Please note that a URL encoded number format is expected by the webhook, so for international +E164 numbers we should replace + per %2B.
Example:
https://:8081/telnyx-conf-v2/pull?number=%2B35193309090
Start recording call leg
https://:8081/telnyx-conf-v2/record-start?participant=x
Stop recording call leg
https://:8081/telnyx-conf-v2/record-stop?participant=x
Lightning-up the application
Finally the last piece of the puzzle is having your application listening for Telnyx Webhooks:Ruby
⏱ 60 minutes build time || Github RepoIntroduction to conferencing
The Voice API framework, previously called Call Control, is a set of APIs that allow complete control of a call flow from the moment a call begins to the moment it is completed. In between, you will receive a number of webhooks for each step of the call, allowing you to act on these events and send commands using the Telnyx Library. A subset of the operations available in the Voice API is the Conference API. This allows the user (you) to create and manage a conference programmatically upon receiving an incoming call, or when initiating an outgoing call. The Telnyx Ruby Library is a convenient wrapper around the Telnyx REST API. It allows you to access and control call flows using an intuitive object-oriented library. This tutorial will walk you through creating a simple Sinatra server that allows you to create and manage a conference.Setting up your environment
Before beginning, please ensure that you have the Telnyx and Sinatra gems installed.- make sure the Webhook API Version is API v2
- Fill in the Webhook URL with the address the server will be running on. Alternatively, you can use a service like Ngrok to temporarily forward a local port to the internet to a random address and use that. We’ll talk about this in more detail later.
conference_demo_server.rb, then write the following to setup the telnyx library.
Receiving webhooks & creating a conference
Now that you have setup your auth token, phone number, and connection, you can begin to use the API Library to make and control conferences. First, you will need to setup a Sinatra endpoint to receive webhooks for call and conference events. There are a number of webhooks that you should anticipate receiving during the lifecycle of each call and conference. This will allow you to take action in response to any number of events triggered during a call. In this example, you will use thecall.initiated and call.answered events to add call to a conference. Because you will need to wait until there is a running call before you can create a conference, plan to use call events to create the conference after a call is initiated.
/webhook, which can be anything you choose as the API doesn’t care; here we just call it webhook.
Telnyx::Call object and store it in the active call list, then call call.answer to answer it if it’s an inbound call.
call.answered event, retrieve the stored call created during the call.initiated event. Then, either create a new conference if this is the first call and there isn’t a conference running yet, or add the call to an existing conference. Note that a call_control_id is required to start a conference, so there must aready be an existing call before you can create a conference, which is why we create the conference here.
Authentication for your conferencing application
Now you have a working conference application! How secure is it though? Could a 3rd party simply craft fake webhooks to manipulate the call flow logic of your application? Telnyx has you covered with a powerful signature verification system! Simply make the following changes:Telnyx::Webhook::Signature.verify will do the work of verifying the authenticity of the message, and raise SignatureVerificationError if the signature does not match the payload.
Conferencing usage
If you used a Gemfile, start the conference server withbundle exec ruby conference_demo_server.rb, if you are using globally installed gems use ruby conference_demo_server.rb.
When you are able to run the server locally, the final step involves making your application accessible from the internet. So far, we’ve set up a local web server. This is typically not accessible from the public internet, making testing inbound requests to web applications difficult.
The best workaround is a tunneling service. They come with client software that runs on your computer and opens an outgoing permanent connection to a publicly available server in a data center. Then, they assign a public URL (typically on a random or custom subdomain) on that server to your account. The public server acts as a proxy that accepts incoming connections to your URL, forwards (tunnels) them through the already established connection and sends them to the local web server as if they originated from the same machine. The most popular tunneling tool is ngrok. Check out the ngrok setup walkthrough to set it up on your computer and start receiving webhooks from inbound messages to your newly created application.
Once you’ve set up ngrok or another tunneling service you can add the public proxy URL to your Connection in the Mission Control Portal. To do this, click the edit symbol [✎] next to your Connection. In the “Webhook URL” field, paste the forwarding address from ngrok into the Webhook URL field. Add /webhooks to the end of the URL to direct the request to the webhook endpoint in your Sinatra server.
For now you’ll leave “Failover URL” blank, but if you’d like to have Telnyx resend the webhook in the case where sending to the Webhook URL fails, you can specify an alternate address in this field.
Complete running Voice API conference application
The api-v2 directory contains an extended version of the tutorial code above, with the added ability to control the conference from the console! See the comments in the code for details on invoking the commands.Voice API Services in Europe
Source: https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-services-in-europe.md
Overview
Telnyx now has a dedicated endpoint - https://api.telnyx.eu, that can be used to help reduce the latency on calls held in Europe. Don’t forget to updateYOUR_API_KEY here.

Please note that all the participants of the conferences and the calls to add to the queue must be in the same region.
L1 Account Restrictions
Source: https://developers.telnyx.com/docs/voice/programmable-voice/l1-accounts-restirctions.mdThe accounts with the L1 verification are restricted in the following way:
-
All machine-generated speak commands are pre-pended with “This is an automated call generated on the Telnyx platform, please report any abuse to fraud@telnyx.com”. This currently includes:
- /v2/calls
- /v2/calls/:call_control_id/actions/transfer
- /v2/calls/:call_control_id/actions/gather_using_audio
- /v2/calls/:call_control_id/actions/gather_using_speak
- /v2/calls/:call_control_id/actions/playback_start
- /v2/calls/:call_control_id/actions/speak
- /v2/calls/:call_control_id/actions/gather_using_ai
- /v2/calls/:call_control_id/actions/ai_assistant_start
- and the TeXML verbs:
- Play
- Say
- AIGather
- Limited to a maximum of 100 outbound calls a day.
- Limited to 10 outbound calls per hour.
TeXML
TeXML Fundamentals
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-fundamentals.md
Overview
TeXML is an XML-based markup language to define call control and processing instructions. When properly configured, Telnyx will fetch TeXML instructions from the user’s application and process the calls accordingly. See Verbs & Nouns.TeXML Application
An instance of TeXML Application is a collection of configuration parameters that defines the interaction between Telnyx and the user’s application:
A TeXML Application can be created through the Telnyx Mission Control Portal
or via the Telnyx API.
Instruction Fetching
See Instruction Fetching.Twilio Compatibility
See Twilio Compatibility.Instruction Fetching
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-instruction-fetching.mdOn inbound calls (PSTN or External SIP to Telnyx), Telnyx fetches TeXML instructions from the URL defined on the TeXML Application associated with the SIP subdomain or phone number. On outbound calls (Telnyx to PSTN or External SIP), there are two ways the user can trigger instructions fetching, the details of which are described below.
Instruction Fetching on Inbound Calls
An instance of TeXML application can have a specific SIP subdomain or phone number assigned to it. When Telnyx receives a call to that SIP subdomain or phone number, Telnyx will fetch the instructions from the URL defined on the TeXML Application.Instruction Fetching on Outbound Calls
Using TeXML Application
Instructions fetching can be triggered by TeXML Calls API. In this case, a TeXML application is required. Example:Using SIP Trunking Connections
The user can configure a SIP trunking connection of any type to “Park Outbound Calls”. When the user initiates an outbound call on that SIP connection, Telnyx will “park” that call leg, fetch the instructions from the URL defined on the connection, and then process the call based on the instructions. In this use case, a TeXML application is not required.HTTP Request Details
When a call is being handled by a TeXML application, Telnyx makes HTTP requests to fetch instructions from the user’s application. These requests include specific parameters that provide context about the call, allowing the user’s application to generate appropriate TeXML responses.- Method: Configurable (GET or POST, default is GET)
- URL: The URL configured for the user’s TeXML application
- Failover URL: Used if the primary URL is unavailable (optional)
Request Parameters
When Telnyx makes a request to fetch TeXML instructions, the following parameters are always included:Optional Parameters
Depending on the call context, additional parameters are added to the request. Full list of the parameters can be found on the documentation page for each of the TeXML verbsParameter Format
Depending on the HTTP method selected for the requests, the parameters are added in the following way:- GET requests - as URL query parameters
- POST requests - in the request body as form-encoded data
Response Requirements
The user’s application should respond with valid TeXML. The response should:- Be valid XML with a root “ element
- Not exceed size limits
- Return HTTP status code 200 OK
Example
Request (GET method)
Response
Best Practices
Here are a few best practices to follow:- Always verify the CallSid parameter to ensure the request is legitimate
- Include error handling in your application to handle unexpected parameters
- Keep response times low to avoid call delays
- Use the parameters to customize call flows based on caller information
- Test your application with various parameter combinations
- By properly handling these parameters, you can create dynamic, responsive TeXML applications that provide excellent caller experiences
TeXML Interpreter
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-interpreter.md
Basic Syntax
A proper TeXML response comprises the following elements:- “ element — tag defining the body of the TeXML document
- verb — an XML tag denoting the desired action
- noun — an XML tag denoting the object of the desired action
Dynamic parameters
When creating a TeXML set of instructions you can make use of Mustache Templates to generate instructions dynamically at runtime.Inserting dynamic content
You can make use of Mustache Dynamic templating to insert content into your TeXML instructions through HTTP request parameters in the webhook URL we use to fetch your TeXML set of instructions. For example, you could create a TeXML set of instructions that calls a number that is set until the HTTP request is made to fetch your TeXML instructions. You first create your TeXML instructions using Mustache Templating and set the{{PhoneNumber}} as a variable like this
PhoneNumber as a parameter.
Iterate through lists
You can set arrays as parameters in your TeXML webhook URL and let Mustache Template handle them. If for example, you want the dial command to have two numbers, you could add aNumbers list parameter to your callback Url.
PhoneNumbers parameter in the TeXML instructions using the following syntax.
Render conditional content
Conditional content is supported by usingif/else statements in the TeXML instructions. You could define a set of instructions to dial a specific number depending on From parameter present in the HTTP request.
==, != and no operator for checking if the parameter value is not null.
TeXML TwiML Compatibility
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-twiml-compatibility.mdTeXML services was created to allow the easy migration from Twilio to Telnyx, allowing you to use the same verbs and nouns in both platforms. This page provides a comparison of verb support between TeXML and TwiML, helping you understand which features are available in each platform.
Verb Compatibility
For detailed information about particular TeXML verb click the link under the name of the verb in the table.
Noun Compatibility
More information about the nouns can be found on “ documentation page
REST API Endpoint Compatibility
The following table outlines the compatibility between Twilio’s REST API endpoints and Telnyx’s TeXML API endpoints.
For detailed information about TeXML REST API endpoints and their usage, please use the links to the documentation from the table.
Dynamic TeXML Bins
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-bin-dynamic.mdIn this guide, we’ll cover how to create dynamic parameters in TeXML Bin using Mustache Templates. You can get started with TeXML Bin in the Mission Control Portal by following the first steps in our previous guide.
Dynamic parameters for TeXML
Mustache is a logic-less web template system used mainly for mobile and web applications. And a great way to generate instructions dynamically at runtime when creating a TeXML set of instructions. By using Mustache Dynamic templating you can insert content into your TeXML instructions through HTTP request parameters in the webhook URL that is used to fetch your TeXML set of instructions. For example, you could create a TeXML set of instructions that calls a phone number which is set until the HTTP request is made to fetch your TeXML instructions. To do this you’ll first need create your TeXML instructions using Mustache Templating, and set the{{PhoneNumber}} as a variable like this:
PhoneNumber as a parameter like so:
Don’t forget to update YOUR_API_KEY here.
Iterating through lists
TeXML Bin allows users to set arrays as parameters in the TeXML webhook url and let Mustache Template handle them. For example, if you want the dial command to have two numbers, you could add aNumbers list parameter to your callback Url.
PhoneNumbers parameter in the TeXML instructions using the following syntax:
How to render conditional content
Conditional content is supported by usingif/else statements in the TeXML instructions. You could define a set of instructions to dial an specific number depending on From parameter present in the HTTP request.
==, != and there is no operator for checking if the parameter value is not null.
Sending HTTP Requests
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-sending-http-requests.mdIn the previous tutorial, we explained how to use dynamic parameters in the TeXML instructions. In this tutorial, we’ll cover how to integrate your systems using HTTP requests from a TeXML file without needing your own server-side application, as well as retrieve required information for call flows from external systems and send notifications to any REST API.
Sending HTTP request
The requests can be sent using “ verb in the following way:- Headers
- The method for the request (GET or POST)
- And the body
Synchronous requests
The requests are sent asynchronously by default. The TeXML process does not wait for the result of the request and immediately executes the next instruction from the TeXML file. It is possible to change that behavior by using theasync attribute and setting it to true. In that case, the TeXML process will wait for the HTTP response and send a callback to the action URL immediately afterward.
Using secrets
API keys or any other secrets can be stored in the secure storage. You can upload them using a dedicated REST endpoint.Sending notifications about the call to your Slack workspace using information about the caller retrieved from Salesforce database
In this section we will present how to retrieve the information about the caller from the Salesforce database and send it as a message to the Slack channel.- Upload an api_key to your Slack workspace under the name slack_api_key
- Upload a token to the Salesforce API under the name salesforce_token
- Create a TeXML file that will send a message to the Slack channel and make a call to your SIP account and name it slack_http_request
- Create a TeXML file that will retrieve the information about the caller and their name from Salesforce.
- Update your TeXML application webhook URL (If you need to create your application, please take a look at this tutorial)

- Make a call to the number associated with the TeXML application and observe the notification in your Slack workspace
TeXML Answering Machine
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-answering-machine.mdTeXML is an XML-based data structure you can use to control calls with Telnyx and is the quickest way to get started with Programmable Voice using a simple .xml file, allowing you to specify call instructions in your file using commands called verbs and nouns.
Initiating a TeXML outbound call using REST endpoint with AMD enabled
There are 2 possible options for using Answering Machine Detection for outbound calls:- Synchronous mode: In this case, the TeXML instructions are not executed until the results of AMD process are provided in the status callback. The new instructions can be sent back as response to be processed by the TeXML engine.
- Asynchronous mode: Here, the TeXML instructions are processed in parallel to the AMD process. The results of the AMD analysis are being provided in the AsyncAmdStatusCallback callback.
Synchronous mode request
The outbound TeXML call with AMD support enable in the synchronous mode can be requested in the following way: Don’t forget to updateYOUR_API_KEY here.
AnsweredBy parameter of the StatusCallback request.
AnsweredBy parameter values
The values returned depend on the MachineDetection mode used:
When MachineDetection is Enable (detects as soon as the answering machine is identified):
When
MachineDetection is DetectMessageEnd (waits for the answering machine greeting to finish):
The
MachineDetection parameter accepts the following values: Enable, Disable (default), and DetectMessageEnd. The DetectionMode parameter accepts Regular (default) or Premium.
Asynchronous mode request
Similarly, the asynchronous AMD processing can be requested for outgoing TeXML calls:AsyncAmdStatusCallback parameter. Note that this can be used for basic and premium AMD.
AsyncAmdStatusCallback parameters
The callback to your AsyncAmdStatusCallback URL includes the following parameters:
Dial
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/dial.mdThe
verb transfers an existing call to another destination. will end this new call if: the called party does not answer, the number does not exist, or Telnyx receives a busy signal.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action Optional URL where TeXML will make a request when the “ call ends to retrieve a new set of TeXML instructions to continue the call flow.verb. It works with the and nouns only. If you want to record the conference, please use the record attribute on noun. Recordings are available in two options: single or dual.
do-not-record, record-from-answer, record-from-ringing, record-from-answer-dual, record-from-ringing-dual
do-not-record
recordingChannels
The number of channels in the final recording. Possible values are: single (for mono) and dual (for stereo). Defaults to single.
single, dual
single
recordMaxLength
Defines the maximum length for the recording in seconds (0 for infinite)
0 - 14400
0
recordingStatusCallback
Optional URL that tells Telnyx where to make its GET or POST request when the recording is available.
or nouns, Telnyx dials each destination one at a time in the order listed. The next destination is attempted only if the current attempt completes without being answered. If omitted or set to false, all destinations are dialed at the same time and the first answered call is connected.
false
passDiversionHeader
When set to true, the Diversion SIP header from the inbound call is passed through to the outbound dial attempt.
false
machineDetectionSpeechThreshold
Maximum duration of a greeting in milliseconds. If a greeting is longer than this value, the call is classified as a machine. Only used when machineDetection is enabled and detectionMode is Premium.
Child verbs/nouns
NOUN/VERB DESCRIPTION Number Specifies a phone number to dial. Sip Thenoun specifies a SIP endpoint to dial. Queue The noun allows you to add a call to a queue.
Number Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT statusCallback A URL for Telnyx to send webhook requests to on each event specified in the statusCallbackEvent attribute for outbound calls only. Inbound Status Callback events can be configured for TeXML the connection settings in the Mission Control Portal.and verbs so that the called party can chose to take an action on the incoming call before the two parties are connected. The callee will continue to hear ringback while the url document is executed.
machineDetection Enables Answering Machine Detection. Note: add amd event type to statusCallbackEvent list to receive the detection result webhook. Enable, DetectMessageEnd, Disable Disable detectionMode Sets the Answering Machine Detection mode. Use PremiumCallScreening for premium iOS call screening detection. See https://developers.telnyx.com/docs/voice/programmable-voice/answering-machine-detection Regular, Premium, PremiumCallScreening Regular machineDetectionTimeout Maximum timeout threshold for overall detection, in milliseconds. 500 - 60000 3500 machineDetectionPromptEndTimeout Silence duration threshold after a call screening prompt before ending prompt detection, in milliseconds. Only used when machineDetection is enabled and detectionMode is PremiumCallScreening. 1000 - 120000
sipRegion The geographic region of the SIP infrastructure Telnyx should use when dialing the destination. US, Europe, Canada, Australia, Middle East USSip Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT username Username to use for SIP authentication.and verbs so that the called party can chose to take an action on the incoming call before the two parties are connected. The callee will continue to hear ringback while the url document is executed.
method HTTP request type used for url. GET, POST POST machineDetection Enables Answering Machine Detection. Note: add amd event type to statusCallbackEvent list to receive the detection result webhook. Enable, DetectMessageEnd, Disable Disable detectionMode Sets the Answering Machine Detection mode. Use PremiumCallScreening for premium iOS call screening detection. See https://developers.telnyx.com/docs/voice/programmable-voice/answering-machine-detection Regular, Premium, PremiumCallScreening Regular machineDetectionTimeout Maximum timeout threshold for overall detection, in milliseconds. 500 - 60000 3500 machineDetectionPromptEndTimeout Silence duration threshold after a call screening prompt before ending prompt detection, in milliseconds. Only used when machineDetection is enabled and detectionMode is PremiumCallScreening. 1000 - 120000
sipRegion The geographic region of the SIP infrastructure Telnyx should use when dialing the destination. US, Europe, Canada, Australia, Middle East USQueue Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT url Optional URL to another TeXML document that can contain, , , and “ verbs. The document will be executed on the queued call before bridging the calls.
Simultaneous dialing
You can use multipleand nouns within a “ verb to dial multiple phone numbers and SIP addresses at the same time. The first person to answer the call will be connected to the caller, while the rest of the call attempts are hung up:
Sequential dialing
Setsequential="true" to dial multiple and nouns one at a time in the order listed. Telnyx attempts the next destination only if the current attempt completes without being answered. If a destination answers, it is connected to the caller and the remaining destinations are not dialed.
Examples
Expected callbacks
Ifaction is set, a callback is sent when the dialed call ends. See Dial Action Callback for the full payload reference.
The error_code and error_message fields are provided only in case of failed calls. The full list of errors can be found under the API Errors page.
If statusCallbackEvent is set, the following webhooks are sent based on configured events:
If
machineDetection is enabled, an AMD callback is sent to amdStatusCallback. See AMD Callback for the full payload reference.
If deepfakeDetection is set to Enable, a deepfake detection callback is sent to deepfakeDetectionCallbackUrl (or to statusCallback if "deepfake" is included in statusCallbackEvent). The callback payload includes DeepfakeResult (real, fake, or silence_timeout), DeepfakeScore (0.0–1.0), and DeepfakeConsistency (0–100). On detection failure, a DeepfakeError field is sent instead.
If recordingStatusCallbackEvent is set, the following webhooks are sent:
Say
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/say.mdThe “ verb speaks the text specified back to the caller, enabling text-to-speech for any application.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT voice Optional text-to-speech voice type. For basic text-to-speech use man or woman (en-US only). For premium text-to-speech use alice or one of the following provider-prefixed formats: Polly.VoiceId / Polly.VoiceId-Neural for Amazon Polly, AWS.Polly.VoiceId for direct AWS Polly notation, Azure.VoiceId for Azure TTS (supports gender and effect attributes), ElevenLabs.ModelId.VoiceId for ElevenLabs (requires api_key_ref), Telnyx.ModelId.VoiceId for Telnyx native TTS, Resemble.ModelId.VoiceId for Resemble AI, Minimax.ModelId.VoiceId for Minimax, Rime.ModelId.VoiceId for Rime, Inworld.ModelId.VoiceId for Inworld, and FishAudio.ModelId.VoiceId for Fish Audio (ModelId is one of s2.1-pro, s2-pro, or s1). man, woman, alice, Polly.VoiceId, Polly.VoiceId-Neural, AWS.Polly.VoiceId, Azure.VoiceId, ElevenLabs.ModelId.VoiceId, Telnyx.ModelId.VoiceId, Resemble.ModelId.VoiceId, Minimax.ModelId.VoiceId, Rime.ModelId.VoiceId, Inworld.ModelId.VoiceId, FishAudio.ModelId.VoiceId man language ISO language type to be used if voice type alice is selected. If man or woman is selected, the language accent will always be en-US. This parameter is ignored when a specific Amazon Polly voice is used.gender Specifies the gender of the voice. Only applicable when using Azure voices (Azure.*). Male, Female
effect Applies an audio effect to the spoken text. Only applicable when using Azure voices (Azure.*). eq_telecomhp8k, eq_car
voiceSpeed Speech rate for the voice. Must be a decimal between 0.1 and 2.0. Defaults to 1. 0.1 - 2.0 1 api_key_ref Reference to the API key for authentication with the TTS provider. The key must be stored via the integration secrets API. Used with ElevenLabs and Azure voices.Examples
Play
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/play.mdThe
verb plays an MP3 or WAV audio file, which Telnyx fetches back to the caller from the URL you configure. Alternatively, specify `mediaStorage="true"` to fetch a file you previously uploaded to Telnyx using media storage APIs. When `mediaStorage="true"` is used the verb expects a `media_name` instead of a URL. You can also use the `digits` attribute to play DTMF tones instead of an audio file. The `ringTone` attribute generates a country-specific ringback tone instead of fetching an audio file; it cannot be combined with an audio body and is not supported inside.
By default, a playback failure (e.g. the audio URL returns 404) aborts the TeXML script. Set continueOnError="true" to log the failure and proceed with the next verb instead.
Set failoverUrl to retry once with a backup audio source before the failure path is taken; continueOnError still applies if the failover also fails.
can be used independently as a verb or nested within as a noun to play an audio file while waiting for DTMF tones.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT loop Times to repeat the audio. When used withringTone, forwarded to FreeSWITCH as the tone_stream loops parameter; loop="0" plays the tone indefinitely until interrupted by a subsequent verb or hangup.
1
mediaStorage
When true fetches the file from Telnyx media storage using the provided media name.
true, false
false
digits
DTMF tones to play. The value can include digits 0-9, *, #, and w (for a 0.5 second pause). When specified, the verb plays DTMF tones instead of an audio file.
mediaStorage flag also applies to this URL. Only one retry attempt is made.
ringTone Plays a country-specific ringback tone instead of an audio file. Cannot be combined with an audio body. Not supported inside “. at, au, bg, br, be, ch, cl, cn, cz, de, dk, ee, es, fi, fr, gr, hu, il, in, it, lt, jp, mx, my, nl, no, nz, ph, pl, pt, ru, se, sg, th, tw, ve, za, us, us-old, uk
Examples
Gather
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/gather.mdThe
verb collects DTMF tones during a call. can be nested within “ to create an interactive IVR with text-to-speech.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action URL where TeXML will send the gathered result and message history. Same method (GET/POST) as set for the TexML application is used. Transfers control of the current call to the TeXML file returned.model="deepgram/nova-2"; it is silently dropped on Nova-3 (use keyterms instead). Accepts a comma-separated string.
model="deepgram/nova-3"; silently dropped on Nova-2 (use hints instead). Accepts a comma-separated string.
transcriptionEngine Engine to use for speech recognition: Google, Telnyx, Azure, Deepgram, xAI, AssemblyAI, Soniox, Speechmatics, Parakeet, Humain Google, Telnyx, Azure, Deepgram, xAI, AssemblyAI, Soniox, Speechmatics, Parakeet, Humain
model Speech recognition model. Format isvendor/model-name — e.g. deepgram/nova-2, deepgram/nova-3, azure/fast, assemblyai/universal-streaming, soniox/stt-rt-v4, speechmatics/standard, nvidia/parakeet-v3, xai/grok-stt, humain/realtime. The vendor must match transcriptionEngine. On Deepgram, defaults to deepgram/nova-3 when unset.
numDigits The number of digits to be gathered.
Child verbs/nouns
NOUN/VERB DESCRIPTION Say PlayExamples
Expected callbacks
Ifaction is set, a callback is sent when gather completes with the collected digits or speech.
See Gather Callback for the full payload reference.
AIGather
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/aigather.mdThe
verb collects specific information from call participants leveraging AI. It requires the child node to be provided with a JSON Schema object that describes the parameters to be gathered.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action URL where TeXML will send the gathered speech input. The same method (GET/POST) as set for the TeXML application is used. Transfers control of the current call to the TeXML file returned.Child verbs/nouns
NOUN/VERB DESCRIPTION Greeting Reads supplied text back to the caller when the gathering starts, if none then nothing will be played when the gathering starts. Voice The voice to be used by the voice assistant. Parameters The parameters are described as a JSON Schema object that needs to be gathered by the voice assistant. It needs to be provided within CDATA tags (see the example below). MessageHistory The message history you want the voice assistant to be aware of, this can be useful to keep the context of the conversation, or to pass additional information to the voice assistant. They can be provided as a list ofnodes. Each node must contain a role attribute that can be either user or assistant. The role attribute is used to determine if the message is from the user or the assistant. The text of the message is provided in the node (see the example below). Tools The list of to be used by the AI assistant. The “ should contain at tool definition in json format. All of the available tools are defined in the Voice API Gather using AI documentation.
Voice Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT name The voice to be used by the voice assistant. Currently, we support ElevenLabs, Telnyx and AWS voices only, for ElevenLabs voices you can pass the voice as ElevenLabs.model_id.voice_id, for Telnyx voices you can pass the voice as Telnyx.model_id.voice_id, for AWS Polly voices you can pass the voice as AWS.Polly.voice_id, we also support this notation for AWS Polly voices: Polly.voice_id Telnyx.NaturalHD.Astra api_key_ref The reference to the ElevenLabs API key to be used for the voice assistant. The API key must be added to the account text-to-speech secrets /v2/text-to-speech/secret. Note: this is only used when using an ElevenLabs voice.Examples
Expected callbacks
Ifaction is set, a callback is sent when the AI gather completes with the collected result and message history.
See AI Gather Callback for the full payload reference.
AIAssistant
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/aiassistant.mdThe “ verb allows you to start a voice assistant on the call.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT id The identifier of the AI assistant. The AI assistant can be created using the AI Assistant API.participantName and participantRole to configure the joining participant.
join is set.
join is set.
user, assistant
user
Examples
action attribute is set on , TeXML makes a request to that URL when the assistant conversation ends and executes the TeXML instructions returned in the response. The request payload includes a `Reason` field describing why the conversation ended (for example `service_error`), so the action endpoint can branch on it — such as returning a to a human agent on error:
Record
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/record.mdThe
verb creates an audio file with the call audio. If a recordingStatusCallback, Telnyx will deliver the URL for the recording to that address once the call has ended. Recording URLs are valid for 10 minutes after the call has ended. All recordings are also available via the Telnyx Mission Control Portal **Note** In addition to recording, the verb supports automatic transcription by setting transcription="true" and providing a transcriptionCallback URL. The transcription result will be sent via webhook.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action Optional URL where TeXML will make a request when the “ ends to retrieve a new set of TeXML instructions to continue the call flow sent with additional request parameters.trim Will remove silence from the beginning and end of the recording when set to trim-silence. trim-silence
channels When using dual channels, the final audio file will be stereo recorded with the first leg on channel A, and the rest on channel B. single, dual dual recordingStatusCallback Optional URL that tells Telnyx where to make its GET or POST request when the recording is available.A uses Google (default) and B uses Telnyx. Set to Deepgram to transcribe the recording with Deepgram, optionally pairing it with transcriptionModel to choose a specific Deepgram model.
A, B, Deepgram, deepgram
A
transcriptionModel
Optional model to use with the specified transcriptionEngine. Format is vendor/model-name — e.g. deepgram/nova-2 or deepgram/nova-3. The vendor must match transcriptionEngine. If not specified, the engine’s default model will be used. On Deepgram, defaults to deepgram/nova-3. See transcription models in transcription_engine_config.
en-US. The set of supported languages depends on the transcriptionEngine and transcriptionModel — see languages in transcription_engine_config.
en-US
format
The format of the recording file.
mp3, wav
mp3
recordingStatusCallbackEvent
The recording events for which Telnyx should send a webhook to the recordingStatusCallback URL. Multiple events are separated by a space.
in-progress, completed
completed
Examples
Example 1Expected callbacks
Ifaction or statusCallback is set, recording status callbacks are sent:
If
transcribe is enabled, a transcription callback is sent to transcribeCallback:
See Transcription Callback for the full payload reference.
Conference
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/conference.mdThe
verb's noun allows you to connect to a conference room. Much like how the noun allows you to connect to another phone number, the noun allows you to connect to a named conference room and talk with the other callers who have also connected to that room. Conference is commonly used as a container for calls when implementing hold, transfer, and barge. If the specified conference name does not exist, a new conference will be created.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT muted Specify whether a participant is muted or not. false startConferenceOnEnter Start the conference when a participant joins. If this is false and the participant joins a conference that has not started, they are muted and hear background music until a participant joins where startConferenceOnEnter is true. This is useful for implementing moderated conferences. true endConferenceOnExit If a participant has this attribute set to true, then when that participant leaves, the conference ends and all other participants drop out. This is useful for implementing moderated conferences that bridge two calls and allow either call leg to continue executing TexML if the other hangs up. false maxParticipants The maximum number of participants allowed in the conference. 2 - 250 250 beep Specify whether a notification beep is played to the conference when a participant joins or leaves the conference. The participant joining the conference will never hear a beep. Note: this attribute does not affect the recording start beep. To disable the beep played when recording starts, set the recordBeep attribute to false. true, false, onEnter, onExit true participantLabel A unique label for the participant which will be added into the conference as a result of executing the TeXML instruction. The label can be used to read or update participant attributes using the TeXML REST API.statusCallbackEvent The conference events for which Telnyx should send a webhook on. Multiple events are separated by a space. start, end, join, leave, speaker
waitUrl A URL to an MP3 or WAV file that should be used for the conference’s hold music before the conference starts. The URL can also return an XML document with instructions that will be executed while the call is waiting for the conference to start.Examples
Expected callbacks
IfstatusCallbackEvent is set, the following webhooks are sent based on configured events:
Enqueue
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/enqueue.mdThe “ verb enqueues the current call in a call queue.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action Defines an absolute or relative URL used to send a request when the call leaves the queue. It will be sent right away when the call is dequeued usingverb. When a call is dequeued using verb, the request will be sent once the bridged calls disconnect.
, , , , , , “.
Examples
Expected callbacks
IfwaitUrl is set, a callback is sent when the call enters the queue. See Queue Callback for the full payload reference.
Hangup
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/hangup.mdEnds the call
Examples
Expected callbacks
When the call ends, a callback is sent to the webhook URL defined on the connection level withCallStatus set to completed.
See Call Completed Callback for the full payload reference.
Pause
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/pause.mdThe
verb waits silently for a specified number of seconds or one second by default. No nouns can be nested within, and a self-closing tag must be used.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT length Seconds to pause 1 - 180 1Examples
Redirect
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/redirect.mdThe
verb transfers control of a call to the TeXML document to another TeXML application. This is useful to create a tree structure of TeXML files for different applications. No nouns can be nested within
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT method The type of requested used “ URL. GET, POST POSTExamples
Reject
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/reject.mdThe
verb rejects a call to your Telnyx number. It is effectively an exit statement from the current document, as there is no way to return to any instructions listed after the verb. If placed as the very first verb in an incoming call, will prevent the call from being answered and will incur no cost. If placed elsewhere in the call, the call will hang up but will be charged up to that point.You can't nest any verbs within and you can’t nest “ in any other verbs.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT reason The tone to play to indicate the reason the call was rejected. rejected, busy rejectedExamples
Stream
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/stream.mdThe “ instruction starts streaming the media from a call to a specific WebSocket address in near-real-time. Audio will be delivered as base64-encoded RTP payloads (no headers), wrapped in JSON payloads.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT url The destination WebSocket address where the stream is going to be delivered.true.
true
Child verbs/nouns
NOUN/VERB DESCRIPTION Parameter Custom key-value parameter to pass to the WebSocket server. Parameters are included in thestart message sent over the WebSocket connection.
Parameter Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT name The name of the custom parameter.Examples
Disabling automatic reconnection
By default,enableReconnect is "true", and the platform will automatically attempt to reconnect the WebSocket stream if it is disconnected. Set enableReconnect="false" to disable this behavior, for example when a disconnection should immediately end the stream.
Expected callbacks
IfstatusCallback is set, stream status callbacks are sent for the following events:
stream-started— Stream has startedstream-stopped— Stream has stoppedstream-failed— Stream failed to start or was interrupted
ConversationRelay
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/conversationrelay.mdThe “ verb routes a call to a ConversationRelay service that provides voice interactions over a WebSocket connection. It provides speech-to-text transcription and allows requesting text-to-speech synthesis for the call over WebSocket.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT url The WebSocket URL of the conversation relay server.Telnyx.Natural.abbie, Telnyx.NaturalHD.astra).
en, fr, es).
deepgram).
true is an alias for any, false is an alias for none.
none, any, speech, dtmf, true, false
any
welcomeGreetingInterruptible
Whether the welcome greeting can be interrupted by the caller. true is an alias for any, false is an alias for none.
none, any, speech, dtmf, true, false
any
dtmfDetection
Whether to enable DTMF detection during the conversation relay session.
false
Child verbs/nouns
NOUN/VERB DESCRIPTION Language Configures a supported language with optional per-language voice and provider settings. Multiple “ elements can be specified to enable multilingual conversations. Parameter Custom key-value parameter passed to the WebSocket server as assistant dynamic variables.Language Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT code The language code (e.g.,en, fr, es).
telnyx, google).
google, telnyx, deepgram).
nova-2).
Parameter Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT name The name of the custom parameter.Examples
Basic usage with greeting and voice
Multilingual with DTMF language selection
Custom parameters
Custom parameters are passed to the WebSocket server as assistant dynamic variables.Non-interruptible greeting
UsewelcomeGreetingInterruptible="none" to ensure the greeting plays fully before accepting input.
Connect
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/connect.mdThe “ verb starts the service defined in the nested noun in synchronous mode. The following instructions will be executed when the service is stopped.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action Optional URL where TeXML will make a request when theservice ends to retrieve a new set of TeXML instructions to continue the call flow. Supported for the and “ nouns.
Child verbs/nouns
NOUN/VERB DESCRIPTION Stream Start media stream over websocket. See the Stream documentation for more information. ConversationRelay Route a call to a ConversationRelay service that provides voice interactions over a WebSocket connection. See the ConversationRelay documentation for more information. AIAssistant Start a voice assistant on the call. See the AIAssistant documentation for more information.Expected callbacks
Ifaction is set, TeXML makes a request to the action URL when the connected service ends and executes the TeXML instructions returned in the response, replacing the remaining call flow. This is supported for the and nouns.
The request payload includes a Reason field describing why the service ended. For , common reasons include `normal` (a transfer is in progress — the call flow continues and the action is not requested), `service_error`, `stt_error`, `handoff`, and `hangup`. The action endpoint can branch on `Reason` to decide how to continue the call — for example, returning a to a human agent when the conversation ended with a server-error reason.
HttpRequest
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/httprequest.mdThe
verb sends a request to the external servers. It consists of 2 child nodes and “
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT async Defines if TeXML process should wait for the request response. When it is set to false, the callback will be sent to the action URL, when the request is processed false action Defines the action url that will be used to send the callback when the request is processed (only if async is set to false)Child verbs/nouns
NOUN/VERB DESCRIPTION Request Thenode defines all the attributes of the request. It can have 2 child nodes and Response The node defines all the attributes of the response. It can have 2 child nodes and
Examples
Expected callbacks
When the HTTP request completes, a callback is sent to theaction URL. See HTTP Request Callback for the full payload reference.
Leave
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/leave.mdThe
verb removes a call from the queue and continues with the next verb after the original. The “ verb doesn’t support any attributes.
Examples
Refer
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/refer.mdThe
verb in Telnyx allows you to transfer a phone call to another SIP infrastructure during a TeXML call. You can initiate it at any point during the call. When you use the verb, Telnyx will replace the original call with a new call to the external system you specify, effectively transferring the call to that system.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT action Optional URL where TeXML will make a request when the Refer verb ends, to retrieve a new set of TeXML instructions to continue the call flow.Examples
Expected callbacks
Ifaction is set, a callback is sent when the “ verb finishes. See Refer Status Callback for the full payload reference.
Siprec
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/siprec.mdThe “ instruction starts the SIPREC session on the given call.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT connectorName Specifies which pre-configured external connector shall be used for this request.Examples
Expected callbacks
IfstatusCallback is set, SIPREC status callbacks are sent for the following events:
siprec-started— SIPREC session has startedsiprec-stopped— SIPREC session has stoppedsiprec-failed— SIPREC session failed to start
Start
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/start.mdThe “ verb starts the service defined in the nested noun. As soon as the service is started, the next TeXML instructions will be executed from the provided instructions.
Child verbs/nouns
NOUN/VERB DESCRIPTION Suppression Start noise suppression. See the Suppression documentation for more information. Transcription Start transcription. See the Transcription documentation for more information. Stream Start media stream over websocket. See the Stream documentation for more information. Recording Start recording the call. See the Recording documentation for more information.Stop
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/stop.mdThe “ verb stops the instruction specified by noun on a call.
Child verbs/nouns
NOUN/VERB DESCRIPTION Suppression Stops current suppression, no attributes need to be provided. Transcription Stops current transcription, no attributes need to be provided. Stream Stops current media stream, no attributes need to be provided.Examples
Suppression
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/suppression.mdThe
noun is used inside and “ verbs to control noise suppression on the call to improve audio quality.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT direction Specifies which side of the audio shall be denoised. inbound, outbound, both inboundnoiseSuppressionEngine
The noise suppression engine to use. Defaults to Denoiser.
Denoiser, DeepFilterNet, Krisp, AiCoustics
model
The Krisp model to use. Only applicable when noiseSuppressionEngine is Krisp. Available models: krisp-viva-tel-v2.kef, krisp-viva-tel-lite-v1.kef, krisp-viva-pro-v1.kef, krisp-viva-ss-v1.kef.
noiseSuppressionEngine is Krisp.
noiseSuppressionEngine is AiCoustics. Valid values: sparrow (default), quail.
noiseSuppressionEngine is AiCoustics. Valid values: s (default), l, vf (vf requires family to be quail). CCA-supported size aliases are also accepted and normalized.
noiseSuppressionEngine is AiCoustics. Defaults to 0.8.
Examples
Start suppression with default settings
Start suppression with Krisp engine
Stop suppression
Transcription
Source: https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/transcription.mdThe “ verb enables real-time speech-to-text transcription for the call.
Attributes
ATTRIBUTE DESCRIPTION OPTIONS DEFAULT language Language to use for speech recognition. See languages in transcription_engine_config. en interimResults Whether to send also interim results. If set to false, only final results will be sent. Applies to transcriptionEngine A only. false transcriptionEngine Engine to use for speech recognition. Available engines: Google (default), Telnyx, Deepgram, Azure, xAI, AssemblyAI, Soniox, Speechmatics, Parakeet, Humain. Each engine supports different models and languages - see model attribute and examples below. Legacy values “A” (maps to Google) and “B” (maps to Telnyx) are supported for backward compatibility. Google, Telnyx, Deepgram, Azure, xAI, AssemblyAI, Soniox, Speechmatics, Parakeet, Humain, A, B Google transcriptionTracks Indicates which leg of the call will be transcribed. Use inbound for the leg that requested the transcription, outbound for the other leg, and both for both legs of the call. inbound, outbound, both inbound transcriptionCallback URL that tells Telnyx where to make its GET or POST requests with transcription data.vendor/model-name — e.g. deepgram/nova-2, deepgram/nova-3, azure/fast, assemblyai/universal-streaming, soniox/stt-rt-v4, speechmatics/standard, nvidia/parakeet-v3, xai/grok-stt, humain/realtime. The vendor must match transcriptionEngine. If not specified, the engine’s default model will be used. On Deepgram, defaults to deepgram/nova-3. See transcription models in transcription_engine_config.
model="deepgram/nova-2"; it is silently dropped on Nova-3 (use keyterms instead). Accepts a comma-separated string.
model="deepgram/nova-3"; silently dropped on Nova-2 (use hints instead). Accepts a comma-separated string.
Examples
Example 1: Basic transcription using Google (default)Expected callbacks
IftranscriptionCallback is set, transcription results are sent as they become available.
See Transcription Callback for the full payload reference.
Applications
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/applications.mdA TeXML application defines how inbound and outbound calls are handled using TeXML instructions. Each TeXML application instance encapsulates a set of configuration parameters that control call behavior, instruction retrieval, and webhook interactions. These parameters determine where Telnyx fetches TeXML from, how call events are handled, and how call flows are executed. More details: Applications
Calls
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/calls.mdA call object represents a single call leg. It contains all state, metadata, and lifecycle information of that call leg.
Creating calls
A call object is instantiated in the following situations: 1. When an outbound call is initiated through the REST API. Telnyx immediately creates a call resource to represent this outbound call. 2. When an inbound call reaches a phone number assigned to a TeXML application.- Before processing any TeXML, a call resource is created to represent the inbound call itself.
- At that point, the call is answered and the instruction fetch request is sent. The lifecycle of this inbound call is driven by the instructions defined in the TeXML response.
Fetching call details
The details of the call can be retrieved using the calls endpoint up to 30 days after the call has ended.Conferences
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/conferences.mdA conference object represents a multi-participant audio session.
Creating conference
A conference is instantiated in the following way: 1. When ato a non-existent is executed
Documentation: “
2. When Telnyx processes a TeXML response that includes a verb with a noun, it attempts to place the current call into a named conference.
Documentation: “
Managing Existing Conferences
Once instantiated, conferences can be managed via REST API endpoints, including:Conference participants
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/conference-participants.mdA conference participant object represents an individual call leg that has been added to a conference.
Creating a conference participant
A conference participant is instantiated in the following situations: 1. When a new participant is dialed and added to a conference via the REST API API reference: dial-a-new-conference-participant. When your application requests to dial a new party into an existing conference using the REST API, a conference participant resource for the new call leg is created. 2. When a call leg is added to a conference viawith in TeXML
Documentation: “
When a TeXML verb that contains a element is executed, the call leg joins the specified conference. At that point, Telnyx creates a conference participant object associated with that call leg.
When Participant API Responses Return No Results
Certain situations cause the participant API to return no participant records, even if the call or conference previously existed. Telnyx will return no participant objects under the following conditions: 1. The conference has been completed Once a conference ends (e.g., all participants disconnect or the session is terminated), Telnyx no longer returns participant objects associated with that completed conference. 2. A participant’s call leg is no longer active (i.e., has been hung up) If a participant disconnects - whether intentionally, due to call failure, or because of application logic - their call leg is considered complete, and the participant object is no longer returned by the API. 3. The participant has been explicitly removed via the REST API API reference: delete-a-conference-participant 4. The participant’s call leg has been given new TeXML instructions via the REST API API reference: update-call If a call leg that was previously in a conference is updated with new TeXML instructions via the REST API, it effectively leaves the conference context. As a result, it is no longer included in participant API responses.Recordings
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/recordings.mdA recording object represents an audio recording generated during a call or conference using TeXML application. Recording objects track metadata such as format, duration, start and end times, and storage locations.
Creating recording
A recording can be created in the following situations: 1. When an outbound call is initiated with record enabled via the REST API API reference: Initiate an outbound call If your application initiates an outbound call and specifies the record attribute, Telnyx automatically begins recording the call when it is answered. 2. When a “ verb is executed in a TeXML script Documentation: “ Whenever averb is encountered in a TeXML response, Telnyx initiates audio capture for the call leg that executed the verb. Each execution produces a distinct recording object that captures the audio during the period
3. When a “ verb is executed with record attributes enabled
Documentation: “
If a “ verb includes recording parameters (e.g., to record the outbound leg created by the dial), Telnyx begins recording as soon as that outbound call leg is created.
4. When a to is executed with record attributes
Documentation: “
When a connects a call into a and recording attributes are provided, Telnyx initiates conference recording.
5. When recording is started manually via the REST API
API reference: Request recording for a call
The recording may be triggered dynamically on any existing call by making a request to the start recording endpoint. When the request is executed, Telnyx creates a new recording object associated with that ongoing call.
6. When a conference participant is dialed and joined via the REST API with recording enabled
API reference: Dial a new conference participant
If a new participant is added to a conference using the REST API and recording is enabled for that action, Telnyx begins capturing audio for the participant or the entire conference session.
Fetching Recordings
Recording objects can be retrieved through several query paths depending on how the recording was initiated: 1. By Recording ID - API reference 2. By Conference ID - API reference 3. By Call ID - API referenceControlling Ongoing Recordings
Once recording is active, your application can manage or modify the recording session using the REST API: 1. Update or stop an ongoing recording on a call - API referenceTranscripts
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/transcripts.md
Transcription Creation
A transcription can be enabled from TeXML in 2 scenarios: 1. When a verb is executed in TeXML Documentation: [](https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/transcription)
When Telnyx processes a TeXML document containing the “ verb, it initiates an audio capture operation based on the parameters defined in that verb. Once the audio is captured and processed, a transcription is provided in statuscallbacks in real-time.
2. When a verb is executed with transcription attributes Documentation: [](https://developers.telnyx.com/docs/voice/programmable-voice/texml-verbs/record)
If a TeXML “ verb includes transcription-related attributes, Telnyx performs transcription on the recorded audio once the recording is complete.
Retrieving recording transcription
Upon completion of the transcription process, a transcription object representing the text output associated with that recording segment is created and can be retrieved using the following endpoint: Fetch a recording transcription resourceSIPREC
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/siprec.mdA SIPREC session represents an active SIP Client Recording (SIPREC) media session associated with a call. SIPREC sessions enable the delivery of call media to an external SIP recording server for compliance recording, monitoring, or archival purposes. Each SIPREC session object encapsulates the configuration, state, and lifecycle of a single recording session tied to a call. In order to use SIPREC, the SIPREC client connectors must be configured in your Telnyx account. See SIPREC client tutorial for more information.
Creating SIPREC session
A SIPREC session can be started in the following ways: 1. Starting a SIPREC session via the REST API API reference: Request a SIPREC session for a call Using the REST API, an application can explicitly request the initiation of a SIPREC session for an active call. When this endpoint is invoked, Telnyx creates a SIPREC session object and begins streaming the call media to the configured SIP recording endpoint according to the supplied parameters. This approach allows SIPREC to be started dynamically at any point during the call lifecycle. 2. Starting a SIPREC session via the TeXML “ verb Documentation: “ The SIPREC session is initiated synchronously (nested to “ verb) as part of the sequential TeXML execution flow. Subsequent TeXML instructions are processed only after the SIPREC session has been stopped.Managing and Stopping a SIPREC Session
Once a SIPREC session has been started—either via the REST API or via TeXML - it can be managed throughout its lifecycle using the REST API. API reference: Update a SIPREC session for a call This endpoint allows an application to update the state of an active SIPREC session or explicitly stop the recording.Streams
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/streams.mdA stream object represents an active media streaming session originating from a call. Streams allow real-time audio from a call to be delivered to an external destination using WebSockets. Each stream object encapsulates the configuration, state, and lifecycle of a single streaming session associated with a call.
Creating stream
A stream object can be started in the following ways: 1. Starting a stream via the REST API API reference: Start streaming media from a call Using the REST API, an application can explicitly start streaming media from an active call. When this endpoint is invoked, a stream object is created and audio begins streaming from the specified call according to the provided configuration. This method allows streaming to be initiated dynamically at any point during the call lifecycle. 2. Starting a stream via the TeXML “ verb Streams can also be initiated as part of TeXML execution using the “ verb, which supports two operational modes:- Asynchronous streaming via “
verb is nested inside a verb, the stream is started asynchronously. In this mode, streaming begins in parallel with the ongoing call flow, allowing audio to be streamed without interrupting or blocking other TeXML instructions.
- Synchronous streaming via “
verb is nested inside a verb, streaming is initiated synchronously. In this mode, the call flow waits for the streaming operation to stop before proceeding to the next TeXML instruction.
In both cases, execution of the “ verb results in the creation of a stream object associated with the active call.
Managing and Stopping a Stream
Once a stream has been started—whether via the REST API or TeXML—it can be managed throughout its lifecycle using the REST API. 1.Updating or stopping a stream via the REST API. API reference: Update streaming on a call When streaming is stopped, the associated stream object transitions to a completed state, and websockets are closed.Queues
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/queues.mdA queue object represents a holding area for calls. Calls in a queue are ordered by the time they were enqueued (First-In-First-Out).
Creating queues
There are two ways to instantiate a new queue: 1. Using the REST API A queue can be explicitly created by sending a request to the Create New Queue endpoint. 2. Using the “ Verb A queue can also be created dynamically during call flow execution. When an “ verb is executed inside a TeXML script with a specific queue name, Telnyx checks if a queue with that name already exists. If the queue exists, the call is added to it. If it does not exist, a new queue is automatically created with default settings, and the call is then added.Managing queues
Once a queue is instantiated, it can be managed using the TeXML REST API. Get detailed information about a specific queue by its Queue SID or name. This returns the current state, including the number of calls currently waiting (current size), the average wait time, and the maximum size configuration. Modify the properties of an existing queue. For example, you can change the maximum number of allowed calls (max size) to prevent overloading the system. Remove a queue from your account.TeXML application secrets
Source: https://developers.telnyx.com/docs/voice/texml/rest-api/secrets.mdThe TeXML Secrets API provides a secure mechanism for storing, managing, and retrieving sensitive information required by your TeXML applications. This includes credentials, API keys, tokens, and other confidential values that should not be hardcoded into TeXML documents or exposed in application source code. See the tutorial for more information.
Creating a Secret
The secret can be created using the following endpoint: Create a TeXML secretSIP Trunking
Overview
Source: https://developers.telnyx.com/docs/voice/sip-trunking/get-started.mdTelnyx SIP trunking uses SIP Connections for inbound traffic and authentication, and Outbound Voice Profiles for outbound call routing.
SIP Connections
SIP connections authenticate traffic with Telnyx SIP proxies and configure inbound call handling.
See Authentication Methods for configuration details.
Outbound Voice Profiles
Outbound voice profiles control outbound call routing, destinations, and spending limits.Network configuration
For SIP signaling addresses, media IP ranges, and port requirements, see sip.telnyx.com.Related pages
Overview
Source: https://developers.telnyx.com/docs/voice/sip-trunking/authentication/credential-types.mdTelnyx SIP connections support multiple authentication methods based on network topology and security requirements.
Methods
Credential-based authentication
Username and password for SIP registration. POST /v2/credential_connectionsP-Charge-Info authentication
SIP header containing a phone number associated with the connection.FQDN authentication
Hostname-based inbound routing combined with credentials or IP authentication for outbound.Comparison
IP Authentication Token
Source: https://developers.telnyx.com/docs/voice/sip-trunking/authentication/ip-authentication-token.mdThe
X-Telnyx-Token header distinguishes multiple SIP connections sharing the same IP address.
Token requirements
SIP header format
Configuration
PATCH /v2/ip_connections/{id}Authentication behavior
Both the source IP and
X-Telnyx-Token value must match the connection configuration.
Tech Prefix
Source: https://developers.telnyx.com/docs/voice/sip-trunking/authentication/tech-prefix.mdA 4-digit identifier prepended to outbound calls to differentiate multiple SIP connections sharing the same IP address.
Dial string format
1234 + destination +18005678912 = 123418005678912
Use cases
- Multiple SIP connections from the same IP address
- Granular call routing and billing per connection
- Traffic stream separation
Configuration
PATCH /v2/ip_connections/{id}Phone system setup
The PBX or SIP client must prepend the tech prefix to all outbound calls on the trunk.Authentication behavior
Alternative authentication methods
For connections sharing an IP address:Caller ID Policy
Source: https://developers.telnyx.com/docs/voice/sip-trunking/configuration/caller-id-policy.mdTelnyx enforces strict caller ID validation to prevent spoofing and ensure compliance with telecommunications regulations. Invalid caller ID numbers are rejected with a
403 Caller Origination Number is Invalid D35 SIP response.
Number format requirements
The accepted caller ID format depends on the connection’s localization setting and call destination.USA localization
Accepted formats:International localization
For non-USA localization (e.g., Ireland):Cross-border calls
When calling outside the localization country, only E.164 format is accepted:+13129457420.
Caller ID override
Connections with Caller ID Override enabled can send any format for outbound calls, bypassing standard validation rules.SIP header priority
Telnyx checks the following SIP headers in order to determine the caller ID:P-Preferred-Identity(User part)P-Asserted-Identity(User part)Remote-Party-Id(User part)FROM(User part)
Caller ID anonymization
To anonymize the caller ID, include thePrivacy: id header in the SIP request:
- A valid origination number must still be provided
- Invalid numbers with this header trigger the D35 error
- Toll-free and emergency number calls cannot be anonymized
- Emergency services (911, etc.)
- Toll-free numbers
International spoofing restrictions
Outbound calls to international destinations with spoofed caller IDs are rejected with a503 error response. This allows implementing fallback routing logic on the client side.
Validation behavior
If no localization is configured and a number appears invalid, Telnyx defaults to USA validation rules. Failed validation returns a404 Invalid Destination response.
Configuration
Set the connection localization in the Mission Control Portal under Connection Outbound Settings, or via the API:Troubleshooting
Concurrent Call Limits
Source: https://developers.telnyx.com/docs/voice/sip-trunking/configuration/concurrent-limits.mdConcurrent call limits control the maximum number of simultaneous outbound calls allowed on an account. This limit applies globally across all outbound voice profiles.
Default limits
New accounts start with a default concurrent call limit that increases based on account verification:Error handling
When the application attempts to establish a call that exceeds the configured limit, Telnyx returns a SIP 403 error:Implementing retry logic
Implement exponential backoff when handling limit errors:Monitoring
Track concurrent call usage to prevent limit errors:Via API
Use GET /v2/calls and filter forstatus: active to get the current concurrent call count.
Webhook monitoring
Track call lifecycle events using Voice API webhooks:call.initiated- Increment countercall.hangup- Decrement counter
Best practices
- Set alerts - Configure monitoring to alert when usage reaches 80% of the limit
- Implement queueing - Queue calls when approaching limits rather than failing immediately
- Monitor trends - Track peak usage patterns to anticipate when limit increases are needed
- Test error handling - Verify the application handles 403 limit errors gracefully
Requesting limit increases
For concurrent call limits exceeding 10 channels, contact support@telnyx.com. Include the following information in the request:- Current concurrent call requirement
- Expected growth trajectory
- Use case description (required for limits exceeding 100 channels)
P-Charge-Info
Source: https://developers.telnyx.com/docs/voice/sip-trunking/configuration/p-charge-info-header.mdA SIP header that identifies the billing number (DID) for outbound calls, enabling accurate call attribution and routing through Telnyx SIP trunks.
Header format
- A valid DID associated with the Telnyx SIP connection
- In E.164 format (e.g.,
+15551234567) - Wrapped in SIP URI format
Use cases
- Multiple DIDs on a single SIP connection
- Call detail record (CDR) attribution per DID
- Billing and usage tracking per number
- Carrier-side call routing based on originating number
Requirements
- Telnyx SIP connection configured for outbound calling
- Valid DID ownership and assignment to the connection
- PBX access to modify dialplan or trunk configuration
Troubleshooting
Alternative identification methods
For connections sharing authentication credentials:Outbound Voice Profiles for SIP trunking
Source: https://developers.telnyx.com/docs/voice/sip-trunking/configuration/outbound-voice-profiles.mdOutbound voice profiles control routing, billing, and rate limits for outbound SIP calls. Each profile generates a unique Profile ID used in API calls and CDR reports.
Profile components
Destinations
Telnyx supports 255 destinations across 10 regions. Enable destinations by region or individual country. Many destinations require Level 2 verification before activation.Channel limits
Channels represent concurrent call capacity. Each active call consumes one channel. Set channel limits per profile to control concurrency and prevent service degradation.Billing configuration
Rate deck
Calls are rated based on destination number prefix. Download current rate decks or request custom rates through an account representative.Max destination rate
Set a maximum per-minute rate threshold. Calls to destinations exceeding this rate are rejected automatically.Daily spend limit
Define maximum spend per day per connection. Limits reset at 00:00:00 UTC. Prevents unexpected overages from misconfigured systems or traffic anomalies.Call recording
Enable recording for all outbound calls or specific ANI numbers.Round Robin Routing
Source: https://developers.telnyx.com/docs/voice/sip-trunking/routing/round-robin-routing.mdRound robin routing distributes inbound calls sequentially across all configured IP addresses in a SIP connection. Each IP receives equal call volume regardless of active call load.
How it works
Calls route to IPs in sequential order:Failover behavior
If the target IP fails, the system attempts remaining IPs in sequence. All IPs function as backups for each other. Example: If IP 2 is selected first and fails, the system tries IP 3, then IP 1.Configuration
PATCH /v2/ip_connections/{id}Limitations
- Only counts inbound call distribution, not active call load
- An IP handling 100 active calls receives the same incoming call rate as an IP handling 10 active calls
Use cases
- Distributing load across multiple PBX instances
- High-availability setups without dedicated failover systems
- Deployments where simple call distribution is sufficient
AnchorSite
Source: https://developers.telnyx.com/docs/voice/sip-trunking/routing/anchorsite-configuration.mdAnchorSite determines which Telnyx Point of Presence (PoP) handles media routing for SIP calls.
Configuration modes
Latency mode
Automatically selects the optimal PoP based on ICMP ping latency measurements to the SIP endpoint. Requirements:- IP/FQDN authentication: Whitelist Telnyx media IP addresses for ICMP.
- Credential authentication: Include username in
Contactheader orX-Telnyx-Usernameheader:
- TeXML: PoP selected based on latency to webhook URL IP.
Manual mode
Explicitly select a PoP for predictable routing behavior. Available PoPs:Configuration
You can configure AnchorSite in the Telnyx Portal by editing an IP Connection: PATCH /v2/ip_connections/{id}:Failover
If the selected PoP is unavailable (maintenance, outage, health check failure), calls automatically reroute through the next available PoP.Failover & Retries
Source: https://developers.telnyx.com/docs/voice/sip-trunking/routing/failover-and-retries.mdTelnyx SIP connections automatically retry failed call attempts through different routes and IP addresses.
Signaling IP addresses
Telnyx uses two geographically redundant signaling IPs per region:Failover behavior
Single route
- SIP INVITE sent from IP1
- On failure, retry from IP2
Multiple routes
- Attempt all routes via IP1 in configured order
- On failure, retry all routes via IP2
Credential authentication
Calls route through the registered KSS instance with three levels of internal failover.Call forward on failure
When enabled, calls that fail on all SIP routes forward to PSTN (up to 10 termination carriers).Response codes
Triggers failover:
Does NOT trigger failover (call considered connected):
DNS configuration
SRV records (recommended):sip.telnyx.com (US), sip-eu.telnyx.com (EU)
SRV records automatically resolve to both IP1 and IP2.
A records (alternative):
Configure separate A records for each signaling IP and add both as routes.
Configuration
PATCH /v2/ip_connections/{id}:IP Whitelisting
Source: https://developers.telnyx.com/docs/voice/sip-trunking/network-configuration/ip-whitelisting.mdFirewall and ACL configuration for Telnyx SIP signaling, media transport, webhook delivery, and AI services.
SIP signaling and media
For current SIP signaling addresses, media IP ranges, supported codecs, and regional FQDNs, see sip.telnyx.com.Port requirements
Webhook IP addresses
Whitelist these CIDR blocks to receive webhook notifications.North America
Europe
Asia-Pacific
These ranges also apply to WebSocket stream connections.
AI Services IP addresses
Whitelist these CIDR blocks if you use Telnyx AI-powered voice services (AI Assistants, TeXML, Conversation Relay, or Call Control API). These are the source IPs from which Telnyx AI services emit webhook tool calls and HTTP callbacks. SIP signaling for AI workloads uses the same edge IPs as the rest of the platform (see sip.telnyx.com).SRV Records
Source: https://developers.telnyx.com/docs/voice/sip-trunking/network-configuration/srv-records.mdDNS SRV (Service) records enable automatic failover and load distribution for SIP connections by resolving to multiple Telnyx signaling IPs with priority and weight parameters.
SRV record format
Telnyx SRV records follow RFC 2782 DNS SRV specification:Parameters
Regional FQDNs
Configure SRV records to point to the Telnyx region closest to the user’s infrastructure:
For the most current IP addresses and additional regions, see sip.telnyx.com.
Configuration examples
Basic configuration
Single SRV record pointing to US region:TLS transport
For encrypted SIP signaling on port 5061:Multi-region redundancy
Route to US as primary, EU as secondary:10 (US) is preferred over priority 20 (EU).
Benefits over A records
Verification
Verify the user’s SRV record configuration:DNS provider configuration
Most DNS providers support SRV records through their control panel or API. Common DNS providers:- Route 53 (AWS): Record type “SRV”, value format
10 10 5060 sip.telnyx.com - Cloudflare: Record type “SRV”, configure service, protocol, priority, weight, port, target separately
- Google Cloud DNS: Use
gcloud dns record-sets createwith--type=SRV
Failover behavior
SRV records work with Telnyx automatic failover:- DNS query resolves
sip.telnyx.comto both IP1 and IP2 - SIP INVITE sent to IP1 (primary)
- On timeout or error, retry to IP2 (secondary)
- If all IPs fail, attempt next priority SRV target (if configured)
Troubleshooting
SRV record not resolving:- Verify trailing dot on target FQDN (
sip.telnyx.com.) - Check TTL has expired if you recently updated
- Confirm DNS propagation:
dig @8.8.8.8 _sip._udp.example.com SRV
- Some PBX systems require explicit SRV lookup enablement
- Configure PBX to use domain (
example.com) not IP address - Check PBX logs for DNS query behavior
- Verify equal weight values for balanced distribution
- Some SIP stacks cache first resolved IP
- Consider implementing client-side round-robin
STUN/TURN
Source: https://developers.telnyx.com/docs/voice/sip-trunking/network-configuration/stun-turn-servers.mdSTUN (Session Traversal Utilities for NAT) and TURN (Traversal Using Relays around NAT) servers enable NAT traversal for SIP clients behind firewalls and private networks.
When to use STUN/TURN
Use STUN/TURN servers when the SIP client is:- Behind a firewall or NAT gateway
- On a private network without public IP addresses
- Unable to receive inbound connections directly
- Experiencing one-way audio issues
Telnyx STUN/TURN endpoints
Telnyx provides the following public endpoints for NAT traversal:Configuration
Standard STUN configuration
Configure the SIP client to use Telnyx STUN servers for NAT traversal:TURN with authentication
TURN requires credentials. Contact Telnyx support to obtain TURN server credentials for the account.Alternative STUN servers
While Telnyx provides its own STUN infrastructure, third-party STUN servers may also be used:Network requirements
Ensure the firewall allows outbound traffic:ICE candidate types
When using STUN/TURN, the client will gather different types of ICE candidates:- host: Local network addresses (cannot traverse NAT)
- srflx: Server reflexive addresses (via STUN)
- relay: Relayed addresses (via TURN)
- prflx: Peer reflexive addresses (discovered during connectivity checks)
srflx(server reflexive via STUN)relay(relayed via TURN)prflx(peer reflexive)
Troubleshooting
One-way audio
If one-way audio occurs:- Verify STUN server is reachable:
stun.telnyx.com:3478 - Check that UDP port 3478 is allowed outbound
- Ensure RTP media ports (16384-32768) are open bidirectionally
Connection failures
If calls fail to connect:- Verify firewall rules allow outbound UDP to port 3478
- Check that the SIP client supports STUN/TURN
- Confirm TURN credentials are correct (if using TURN)
- Review ICE candidate gathering logs in the client
Restrictive networks
In highly restrictive networks that block UDP traffic:- Use TURN over TCP:
turn.telnyx.com:3478(TCP) - Consider using TLS for SIP signaling: port 5061
- Contact support for additional configuration options
See also
- IP Whitelisting - Firewall configuration for SIP signaling
- WebRTC Troubleshooting - ICE candidate debugging
Noise Suppression
Source: https://developers.telnyx.com/docs/voice/sip-trunking/features/noise-suppression.mdNoise suppression enhances call quality by removing background noise from audio streams. Configure this feature at the connection level or individual phone number level to reduce unwanted ambient sounds during calls.
Configuration scope
Noise suppression can be configured at two levels:- Connection level: Applied to all phone numbers associated with the SIP connection. This setting overrides individual number configurations.
- Number level: Applied to specific phone numbers for granular control.
Configuration via API
Configure at connection level
PATCH /v2/ip_connections/{id} with thenoise_suppression object:
Configure at number level
PATCH /v2/phone_numbers/{id}/voice with thenoise_suppression object:
Supported engines
Use thenoise_suppression_engine parameter to select an engine. If omitted, Denoiser is used.
For SIP trunking, Denoiser and Krisp Viva Tel Lite are the most common choices. Use
Krisp Viva Tel Lite when you need to isolate the primary speaker from background voices.
Direction options
Thedirection parameter controls which audio streams are processed:
Codec compatibility
Noise suppression works with standard SIP trunking codecs including:- G.711 (μ-law and A-law)
- G.722
- Opus
Performance considerations
- Each direction (inbound/outbound) is processed and billed independently
- Processing adds minimal latency (typically < 20ms)
- Noise suppression is applied in real-time during the call
- Connection-level configuration provides consistent behavior across all numbers
Best practices
- Use connection-level configuration for consistent audio quality across all phone numbers
- Enable bidirectional suppression (
both) for optimal results in noisy environments - Test with your specific use case to balance noise reduction with audio naturalness
- Monitor call quality metrics to validate the impact on your application
Jitter Buffer
Source: https://developers.telnyx.com/docs/voice/sip-trunking/features/jitter-buffer.mdJitter buffering smooths out packet arrival variation on SIP connections to reduce audio artifacts such as choppy or distorted speech. Enable this feature at the connection level to improve call quality on networks with inconsistent latency.
How it works
An adaptive jitter buffer temporarily holds incoming voice packets before playing them out, compensating for uneven packet arrival times (jitter). The buffer dynamically adjusts its size between configurable minimum and maximum values based on observed network conditions — expanding when jitter increases and shrinking when the network stabilizes.Configuration settings
jitterbuffer_msec_min cannot exceed jitterbuffer_msec_max. The API will reject requests where the minimum is greater than the maximum.
Configuration via API
Credential connections
PATCH /v2/credential_connections/{id}FQDN connections
PATCH /v2/fqdn_connections/{id}IP connections
PATCH /v2/ip_connections/{id}Tuning guidance
- Higher values increase latency tolerance and work better for high-jitter networks (e.g., international routes or mobile carriers).
- Lower values reduce latency and are suited for stable, low-jitter networks (e.g., dedicated fiber or local connections).
- Default values (
60–200ms) work well for most deployments and are a good starting point.
Best practices
- Start with defaults before tuning — the default range of 60–200 ms handles most network conditions
- Monitor call quality metrics after enabling to validate the impact on your specific traffic
- Increase the maximum for routes with known high jitter rather than raising the minimum, which adds baseline latency to all calls
- Enable on specific connections rather than globally if only certain routes experience jitter issues
- Test during peak hours when network congestion and jitter are most likely to occur
External Transfers
Source: https://developers.telnyx.com/docs/voice/sip-trunking/features/external-transfers.mdExternal transfers move an inbound PSTN call to an external destination while preserving the original caller’s identity.
Call flow
- Caller A dials Telnyx number B
- Telnyx routes the call to the SIP endpoint (A → B)
- The endpoint initiates a transfer to external number C
- Telnyx places a new outbound call (A → C)
Validation requirements
Telnyx validates external transfers to prevent unauthorized call spoofing:- Active call verification: An active inbound call must exist from the original caller to the Telnyx number
- Diversion header: The outbound call leg must include a SIP
Diversionheader containing the Telnyx number
Transfer types
Blind transfer
Immediate transfer without announcement:Attended transfer
- Place the original call on hold
- Dial the transfer destination
- Announce the transfer
- Complete with SIP REFER
Programmable Voice implementation
Transfer command
POST /v2/calls/{call_control_id}/actions/transfer:Dial with bridge
POST /v2/calls withlink_to and bridge_intent:
TeXML Dial
\ verb:Troubleshooting
If transfers fail, verify:- An active inbound call exists on the Telnyx number
- The Diversion header includes the correct Telnyx number
- The outbound voice profile allows calls to the destination
- The destination number is in E.164 format
SIP URI Calling
Source: https://developers.telnyx.com/docs/voice/sip-trunking/features/sip-uri-calling.mdSIP URI calling enables inbound calls to a SIP username, eliminating the need for a traditional phone number. This feature allows direct communication using SIP addresses in the format
username@sip.telnyx.com.
Prerequisites
- Active SIP connection with credential authentication
- SIP device or softphone registered with connection credentials
- Feature enabled on the connection’s inbound settings
SIP URI format
Calls are placed to the SIP username using the standard SIP URI format:- Must begin with a non-numeric character
- This restriction prevents number spoofing and unauthorized dialing
support@sip.telnyx.compbx-main@sip.telnyx.comalice123@sip.telnyx.com
123456@sip.telnyx.com(starts with numeric character)
Configuration
Access control options
Configure SIP URI calling access using one of three modes:Configure via API
PATCH /v2/ip_connections/{id} with thesip_uri_calling_preference parameter:
disabled, unrestricted, or internal based on security requirements.
Making SIP URI calls
From Telnyx SIP connections
Dial directly to the SIP URI from any registered SIP endpoint:From external systems
When configured asunrestricted, external SIP systems can place calls:
Receiving SIP URI calls
Configure the SIP endpoint to accept incoming calls:- Register the SIP device using the connection credentials
- Enable SIP URI calling with the appropriate access control
- Configure the dial plan or routing rules to handle incoming calls
Billing
Identifiable sources
Calls from Telnyx SIP connections use standard rate deck pricing based on the originating connection’s pricing plan.Unidentifiable sources
When SIP URI calling is set tounrestricted, calls from external or unidentifiable sources are billed at $0.002/minute to the connection owner.
Monitor usage when enabling unrestricted access to prevent unexpected charges from public internet traffic.
Security considerations
- Username validation: Non-numeric username requirements prevent unauthorized number spoofing
- Access control: Use
internalmode for private communications within the organization - Rate monitoring: Track call volumes and sources when using
unrestrictedmode - Authentication: Credential-based connections provide secure endpoint registration
Troubleshooting
If SIP URI calls fail, verify:- SIP URI calling is enabled on the connection
- Username begins with a non-numeric character
- Access control mode permits the calling source
- SIP endpoint is properly registered with valid credentials
- Firewall rules allow SIP traffic to/from Telnyx infrastructure
Attestation Behavior
Source: https://developers.telnyx.com/docs/voice/stir-shaken/attestation-behavior.mdAttestation levels assigned by Telnyx for outbound calls.
Outbound calls
Certificate selection
Call forwarding
When call forwarding is enabled on a Telnyx number:- Original STIR/SHAKEN passport preserved or passed through
- DIV (diversion) passport added for forwarded leg with Attestation A
Call transfers
*A if from number is owned, B otherwise.
Hosted Certificate
Source: https://developers.telnyx.com/docs/voice/stir-shaken/hosted-cert.mdUse a self-hosted STIR/SHAKEN certificate to sign outbound calls.
Requirements
- STIR/SHAKEN certificate from an authorized STI-CA
- Certificate hosted at a public HTTPS URL (
x5u) - Unencrypted PEM-format private key (EC-P256 or RSA-2048)
- Outbound voice profile
- US phone number (for validation)
Upload certificate
POST /v2/stir_shaken_certs
Associate with outbound voice profile
PATCH /v2/outbound_voice_profiles/{id}Verify signing
To verify the certificate is signing calls:- Create an IP connection with “Receive SHAKEN/STIR Identity SIP header” enabled
- Assign a US phone number to this connection
- Place a call from a connection using the configured outbound voice profile
- Check the inbound INVITE for the
Identityheader:
Cost
$100 per certificate per month.SIP Header Parameters
Source: https://developers.telnyx.com/docs/voice/stir-shaken/sip-header-parameters.mdTelnyx provides call attestation information through the
verstat parameter in the P-Asserted-Identity SIP header.
Verstat parameter
Call scope
Theverstat parameter is included for:
- Inbound calls from the PSTN
- On-net calls between Telnyx customers
Dynamic E911
Source: https://developers.telnyx.com/docs/voice/sip-trunking/emergency-calling-dynamic-e911.mdDynamic E911 delivers location information to PSAPs during emergency calls. Two methods available:
API-based addresses
Pre-provision addresses and endpoints, then reference IDs in SIP headers during calls. Dynamically provisioning emergency endpoints may result in a delay before the associated address is fully available for routing. Telnyx recommends pre-provisioning a persistent emergency address rather than relying on just-in-time provisioning. In circumstances where an emergency call (e.g., 911) is initiated before a dynamically provisioned endpoint is fully activated, the call will be routed to a national emergency call center (PSAP) .Create emergency address
POST /v2/dynamic_emergency_addressesid- Address UUID for endpoint associationsip_geolocation_id- Include inGeolocationheaderstatus-pendingduring validation,activatedwhen ready
Create emergency endpoint
POST /v2/dynamic_emergency_endpointssip_from_id- Include inFromorP-Asserted-Identityheader
SIP INVITE format
Include both IDs in emergency call INVITE:P-Asserted-Identity:
GPS coordinates (PIDF-LO)
Pass real-time coordinates in PIDF-LO format for mobile devices, wearables, and IoT.Coordinate format
SIP INVITE Format for PIDF-LO with GPS Coordinates
SIP INVITE Format for PIDF-LO with MiMe
PIDF-LO requirements
Testing
Use test number933 to simulate emergency calls without dispatching services.
Address field limits
*Common terms auto-abbreviated: APARTMENT→APT, FLOOR→FL, SUITE→STE, BUILDING→BLDG, ROOM→RM
Response Codes
Source: https://developers.telnyx.com/docs/voice/sip-trunking/troubleshooting/response-codes.mdTelnyx-specific SIP response codes for diagnosing call failures.
D-Series Codes (4XX Responses)
Client-side errors related to account configuration, limits, and permissions.D1X: Account & Connection Issues
D2X: Profile & Channel Limits
D3X: Connection & URI Issues
D4X: Routing & Destination Issues
D5X: Channel Billing & Verification
D6X: Account Tier Restrictions
D7X, D8X, D9X: Additional Restrictions
P-Series Codes (Protocol Issues)
SIP protocol violations or proxy-level issues.P0X: Protocol Violations
R-Series Codes (Registration & Authentication)
SIP registration and authentication issues.Routing & Media Codes
PE-Series: Routing Failures
T-Series: Termination Issues
B-Series: Media Issues
488 Not Acceptable Media
Media negotiation failures:Configuration Overview
Source: https://developers.telnyx.com/docs/voice/sip-trunking/configuration-guides.mdThe following Configuration Guides are intended to help you connect your SIP Infrastructure (IP-PBX, SBC, etc) to a Telnyx Elastic SIP Trunk. Be aware, due to the large number of versions, variations, add-ons, and options for many of these systems, the settings you see may differ from those shown in our Configuration Guides. As such, these documents are intended as general guidelines, rather than configuration templates. There is an assumption of familiarity with your network and SIP infrastructure, and how they work.
Guide Listing
Telnyx cannot provide direct support for third-party products; you should contact the manufacturer for your PBX/SBC for assistance in configuring such products. Vendor Version Type Qualified for Secure Trunking 3CX V18 with IP trunk IP-PBX Yes 3CX V18 with credentials trunk IP-PBX Yes 3CX V16 with IP trunk IP-PBX Yes 3CX V16 with credentials trunk IP-PBX Yes 3CX V15 with IP trunk IP-PBX Yes 3CX V15 with credentials trunk IP-PBX Yes 3CX V14 with IP trunk IP-PBX Yes 3CX V14 with credentials trunk IP-PBX Yes Oracle Acme Packet E-SBC Yes Acrobits Groundwire, Softphone Softphone Yes Alcatel SD601 SIP door phone Yes Algo 8xxx Series IP phone Yes Amazon AWS n/a VXC Yes Asterisk n/a: Credentials trunk PBX Yes Asterisk n/a: IP trunk PBX Yes Audiocodes 400HD IP phone Yes Audiocodes E-SBC Yes Auth0 SAML identity proivder SaaS solution n/a Avaya PBX Yes Bicom PBXware PBX Yes BuddyTalk BT110/120 Smart speaker/speakerphone Yes Cisco 68xx/88xx IP phone Yes Cisco CME with IP trunk Softphone Yes Cisco CME with credentials trunk Softphone Yes Cisco CUBE/CUCM with IP trunk SBC Yes Cisco CUBE/CUCM with credentials trunk SBC Yes Cisco SPA112/122 IP phone Yes CounterPath Bria Teams Softphone Yes CounterPath Bria Solo Softphone Yes Dinstar C60 IP phone Yes Elastix by 3CX Elastix 5 with credentials trunk PBX Yes Elastix by 3CX Elastix 5 with IP trunk PBX Yes Elastix by 3CX Elastix 4 with credentials trunk PBX Yes Elastix by 3CX Elastix 4 with IP trunk PBX Yes Epygi QX series PBX Yes Fanvil H5 Hotel IP phone Yes Fanvil X4G IP phone Yes Fanvil X2CP/X2C/X2P Call center IP phone Yes Fanvil X1/X1P IP phone Yes Fanvil V-Series IP phone Yes Fanvil H3 Hotel IP phone Yes Fanvil XU Series IP phone Yes Fanvil H2U IP phone Yes Fanvil X Series IP phone Yes Fanvil X7 Series IP phone Yes Fanvil H3W/H5W WiFi IP phone Yes Fanvil A32i IP phone Yes Flyingvoice All IP phone Yes Fortinet FortiFone FON-375/175/H25 IP phone Yes Fortinet FortiFone FON-570 IP phone Yes FreePBX v15 with credentials trunk: PJSIP PBX Yes FreePBX v15 with IP trunk: PJSIP PBX Yes FreePBX v15 with credentials trunk: ChanSIP PBX Yes FreePBX v14 with IP trunk: ChanSIP PBX Yes FreePBX v14 with credentials trunk: ChanSIP PBX Yes FreePBX v13 with IP trunk: ChanSIP PBX Yes FreePBX v13 with credentials trunk: ChanSIP PBX Yes FreePBX v13 with credentials trunk: PJSIP PBX Yes FreeSWITCH Credentials trunk Device Yes FreeSWITCH IP trunk Device Yes FusionPBX n/a: Credentials trunk PBX Yes Gigaset A510 IP phone Yes Gigaset DX800a IP phone Yes Gigaset A690/AS690 IP phone Yes GOautodial n/a: Credentials trunk PBX Yes GOautodial n/a: IP trunk PBX Yes Google VPC n/a VXC Yes Grandstream GDS3710 Video door system Yes Grandstream Wave Lite Softphone Yes Grandstream GXV3370 IP phone Yes Grandstream GXP1700 Series IP phone Yes Grandstream GXP21XX Series IP phone Yes Grandstream GDS3710 Series Video door system Yes Grandstream GRP2612/GRP2612P/GRP2612W Series IP phone Yes Grandstream GXP IP phone Yes Grandstream GRP260x Series IP phone Yes Grandstream DP752 IP phone Yes Grandstream UMC6202 with IP trunk IP-PBX appliance Yes Grandstream UMC6202 with credentials trunk IP-PBX appliance Yes Grandstream GXP16XX Series IP phone Yes Grandstream UCM6xxx Series IP phone Yes Grandstream HT802 ATA Yes GSuite by Google GSuite SAML Identity Provider SAML identity provider n/a Konftel 300IPx Conference IP phone Yes Konftel 300Wx Conference IP phone (wireless) Yes LastPass n/a SAML identity provider n/a Linphone n/a Softphone Yes Mediatrix C7/4100 Analog adapter/media gateway Yes Megaport n/a Cloud netoworking solution Yes MicroSIP n/a Softphone Yes Microsoft Azure AD SAML Identity Provider SAML identity provider n/a Microsoft Azure n/a VXC Yes Microsoft Teams Call2Teams Office 365 add-on Yes Microsoft Microsoft Teams E-SBC Yes Mitel 5320E/5330E/5340E SIP phone Yes Mitel 6800/6900 SIP phone Yes NCH Software ExpressTalk Softphone Yes Okta Okta SAML Identity Provider SAML identity provider n/a OneLogin OneLogin SAML Identity Provider SAML identity provider n/a OSDial n/a Predictive dialer Yes Panasonic KX-HDV IP phone Yes Panasonic TGP 550 IP phone Yes PBXes n/a PBX Yes PhoneSuite Voiceware, Voiceware Express/Express +, Voiceware Series 2 PBX Yes Plantronics/Polycom Poly OBi300 VoIP adapter Yes Plantronics/Polycom VVX 300-series IP phone Yes Positron IP304/IP304C, IP408/IP408C, IP410C/IP410G SIP phone Yes Positron G-Series PBX device Yes Ribbon EdgeMarc 6000 E-SBC Yes Sansay VSXi E-SBC Yes ScopServ ScopTEL PBX Yes SIPfoundry sipXecs PBX Yes Skype Skype for Business (Office 365) E-SBC Yes SNOM M100 KLE IP phone base station Yes SNOM Professinoal D7xx Series Desk phone Yes SNOM C520 Conference phone Yes Synway UC-200 PBX Yes Thirdlane n/a PBX Yes Ubiquiti Unifi Talk with credentials trunk PBX Yes Ubiquiti Unifi Talk with IP trunk PBX Yes Vicidial n/a: IP trunk Contact center suite Yes Vicidial n/a: Credentials trunk Contact center suite Yes VitalPBX n/a PBX Yes Vodia n/a PBX Yes Voice Elements by Microsoft .NET n/a Development environment Yes Vtech VCS754 ErisStation Conference phone Yes Wildix n/a PBX Yes Xorcom Complete PBX PBX Yes Yealink n/a IP phone Yes Yealink Yeastar S-Series PBX Yes Zoiper Zoiper Communicator Softphone Yes Zoiper 5 Pro Softphone Yes Zoiper 3 with Linux Softphone Yes Zoiper 3 with MacOS Softphone YesLiveKit
Source: https://developers.telnyx.com/docs/voice/sip-trunking/livekit-configuration-guide.md
Purpose of this document
This configuration guide is designed to help you establish and optimize a SIP Trunk between Telnyx, a global leader in VoIP communications, and LiveKit, a robust platform for building real-time audio and video applications. The primary objective of this document is to provide a comprehensive, step-by-step approach for configuring your SIP Trunk setup. This guide caters to both beginners and experienced professionals, ensuring that all readers can effectively integrate these two powerful services. By the end of this guide, you will be able to: **1. Set Up Telnyx: ** Configure your Telnyx account and SIP Trunk settings to prepare for integration. 2. Configure LiveKit: Adjust your LiveKit settings to accept and manage Telnyx SIP Trunk communications. 3. Add Custom X-Headers: In your app setX-Telnyx-Username: to ensure your calls are properly routed. username has to be same value as your authentication username.
4. Debug and Optimize: Troubleshoot common issues and fine-tune your configuration for optimal performance.
Configuration in Telnyx Mission Control Portal
Follow the steps below to create a SIP connection to your LiveKit account. Your checklist:-
- Have an account created on Telnyx portal
-
- Complete L2 verification process
-
- Purchase a number to be used for the voice calls
1. SIP Connection
- In the Telnyx Mission Control Portal choose a “Real-Time Communications” -> “Voice” -> “SIP Trunking” menu on the left sidebar
- Click “Add SIP Connection” button

- Provide a name for your new SIP Connection
- Select FQDN as a type of connection
- Create a sip connection

- Choose “FQDN” as a connection type
- Provide SIP URI obtained from your LiveKit account. You can find it in your project settings page.
- Save FQDN settings with “Add” button

- Switch to the “Outbound Calls Authentication” tab in the Authentication & Routing Configuration section
- Choose “Credentials” for the Authentication Method
- Provide your user name and password which will be used later for the LiveKit outbound trunk configuration

- On top of SIP Connection page switch to the Outbound tab
- Select an existing Outbound Voice Profile from a dropdown list.
- If no profile is available you can create a one with a “Create New Outbound Voice Profile” link

- Finally save your sip connection with a “Save” button at the bottom of the page

2. Programmable Voice Applications
Integration over SIP trunk with LiveKit allows also to redirect voice calls originated from LiveKit to Telnyx Voice AP applicationsI. With that option you can implement advanced voice applications with the features like listed below:- Call recording
- IVR (Interactive Voice Response)
- TTS (Text-To-Speech)
- STT (Speech-To-Text / Call transcription)
- Conversational AI (Voice bots with different AI models)
- and many more
- Switch to a “Real-Time Communications” -> “Voice” -> “Programmable Voice” menu on the left sidebar
- Create a new application with an “Add New App” button
- Provide a name for your application
- Configure webhooks URL to receive webhooks about call status changes

- In the Inbound section provide a subdomain name (later you need to use it in a LiveKit outbound trunk setup)
- In the Outbound section select an outbound voice profile
- Save the voice app configuration

3. Outbound Voice Profile
- Switch to a “Real-Time Communications” -> “Voice” -> “Outbound Voice Profile” menu on the left sidebar
- Add a new Profile and provide a name for it
- Or you can adjust the existing profile with clicking on the edit icon

- Select the destinations which should be allowed to make outbound calls to
- Click “Save” button to confirm your configuration

4. Number configuration
- Switch to a “Real-Time Communications” -> “Voice” -> “My Numbers” menu on the left sidebar
- For the number(s) you would like to use for the LiveKit voice participants, select your LiveKit sip connection from a dropdown list presented in the “SIP connections” column
- Update your configuration with a “Save” button
- You can purchase additional numbers in a “Buy Numbers” menu
- The same SIP connection may be assigned to multiple numbers

Configuration in LiveKit
Follow the steps below to configure a SIP trunk for your LiveKit account. Your checklist:-
- SIP URI is available in your project settings
-
- LiveKit CLI is installed on your computer
-
- ENV variables have been configured
1. Create Inbound SIP Trunk
- Create a json file (inboundTrunk.json) with the configuration of your inbound sip trunk
- Provide a name for your trunk and a number to be used (or an array of the comma delimited numbers)
- Run LiveKit CLI command to create an inbound trunk
- In the response you will receive a trunk ID
2. Create Inbound Dispatch Rule
- Create a json file (dispatchRule.json)
- Provide a name for your rule, a trunk ID from the previous step and room name to which incoming calls should be connected
- Run LiveKit CLI command to create a dispatch rule
3. Create Outbound SIP Trunk
- Create a json file (outboundTrunk.json) with the configuration of your outbound sip trunk
- Provide a name for your trunk
- In the address parameter provide “sip.telnyx.com” if you configured a SIP connection on Telnyx side
- If you want to make calls to the configured Voice App, for the address parameter provide a subdomain configured in the Inbound section of your voice application
- Provide username and password you set in your sip trunk configuration for the Outbound Calls Authentication.
- Credentials should be left blank when connecting to the subdomain of your Voice App.
- Run LiveKit CLI command to create an outbound trunk
- In the response you will receive a trunk ID
4. Set custom headers when sending SIP INVITEs
To make sure every outbound call is authenticated against your Telnyx SIP trunk and account, you should send your Telnyx SIP username in a custom SIP header on the very firstINVITE.
Why this is importantTelnyx supports two ways to authenticate SIP calls:
- Credential (SIP digest) authentication
- Using a username and password.
- IP-based authentication
- Matching calls by their source IP address.
INVITE without a username. In that case, Telnyx will:
- Try to match the call to any existing SIP IP connection whose IP matches the source IP.
- Only send a
407 Proxy Authentication Requiredchallenge if no matching IP connection is found.
- It won’t send the 407 challenge.
- It will treat the call as authenticated as that other connection, not your FQDN trunk.
- This can lead to calls being billed or routed under the wrong trunk/account.
- LiveKit sends an
INVITEto Telnyx with your username in a custom header. - Telnyx sees the username and responds with
407 Proxy Authentication Required. - LiveKit sends a second
INVITEwith the username + encrypted password. - Telnyx validates the credentials and authenticates the call against your FQDN connection.
Important: The header value must exactly match the username you configured for credential authentication on your Telnyx FQDN connection (for example, the one you set in the Telnyx Portal or via the API).Example configuration (LiveKit trunk JSON)
authUsernameis your unique Telnyx SIP usernameX-Telnyx-Usernameis the custom SIP header Telnyx will read- The
headers_to_attributesmapping tells LiveKit to populateX-Telnyx-Usernamewith the same value asauthUsername
5. Testing Outbound Calls
- To test an outbound call you can initiate a call with a CLI command
- Create a json file (sipParticipant.json) providing outbound trunk ID obtained in the previous step
- Provide a number to be called in a sip_call_to parameter
- Provide a room name, participant identity and name
- Run LiveKit CLI command to make an outbound call
Troubleshooting
In Telnyx Mission Control Portal we are providing debugging tools where you can troubleshoot any issues with your SIP trunk communication checking SIP call flows, QoS stats and communication to a defined webhooks.1. Debugging tool
- Go to the “Debugging” menu under “Reporting” in the left menu
- Select “SIP Call Flow Tool” on the top bar
- Specify your search criteria and press “Search CDRs” button
- From the list of listed calls select a one with “Call Data Debugging” button




References
-
- Telnyx SIP trunk configuration data - https://sip.telnyx.com
-
- Telnyx SIP trunk setup - https://support.telnyx.com/en/articles/8096455-how-to-configure-a-sip-trunk
-
- LiveKit SIP configuration - https://docs.livekit.io/sip/
UAC Connections
UAC Connections
Source: https://developers.telnyx.com/docs/voice/uac-connections.mdSIP Attach is the Telnyx product for connecting your existing PBX or SIP platform directly to Telnyx. To use SIP Attach, create a UAC Connection. A UAC Connection lets Telnyx register to your PBX as a SIP endpoint. This is the reverse of a typical SIP Credential Connection, where your PBX registers to Telnyx. After registration succeeds, calls can move between your PBX and Telnyx resources, such as AI Assistants or Call Control Applications, over SIP. This lets you connect existing SIP infrastructure to Telnyx services without adding a PSTN phone-number hop.
Create a Connection
POST /v2/uac_connectionsconnection_name is the only required field. You can also provide user_name and password at creation time — if omitted, Telnyx auto-generates them.
Connection Fields
Note:fqdnandregistration_statusare automatically generated by Telnyx.user_nameandpasswordare auto-generated if not provided.
External Settings (external_uac_settings)
These are the SIP credentials Telnyx uses to register to your PBX. The proxy field is required — it’s the SIP server address Telnyx will register to. username and password are the SIP credentials for that registration. transport specifies the transport protocol (TCP, UDP, or TLS).
PATCH /v2/uac_connections/{id}
Internal Settings (internal_uac_settings)
These route inbound calls from the PBX to a Telnyx application. The key field is destination_uri — a SIP URI that tells Telnyx where to send the call.
destination_uri format
Examples:
PATCH /v2/uac_connections/{id}
Full Example
Create a UAC connection with all settings in a single request:Manage Connections
WebRTC
Fundamentals
Source: https://developers.telnyx.com/docs/voice/webrtc/fundamentals.md
What & Why
These SDKs enable client-side applications to instantiate and control a Telnyx call leg. As a result, developers of applications integrated with Telnyx voice platform are no longer constrained to working with inflexible and uncustomizable SIP UAs such as PBX, Asterisk, Zoiper etc. Instead they can embed native voice capabilities client-side to work seamlessly with their voice application and achieve end to end visibility and control of the user experience.How
These SDKs- Utilize the native client-end (browser or device) WebRTC API for cross browser/device compatibility, …
- Adhere to the WebRTC standardization where Media is transported via RTP over DTLS, aka SRTP, aka DTLS-SRTP, … and
- Implements the WebRTC session negotiation, aka signaling, via JSON-RPC messages over Secure WebSocket (WSS).
Availability
The following SDKs are offeredArchitecture
Source: https://developers.telnyx.com/docs/voice/webrtc/architecture.mdTo properly architect solutions and/or troubleshoot issues, one must understand how WebRTC Voice SDK fits among Telnyx’s product portfolio.

WebRTC Voice SDKs CANNOT be used on its own for calling
They merely lower the barriers for users to incorporate voice functionalities in their applications, i.e. instantiate a call leg.rtc.telnyx.com acts as the translation layer where on the SDK facing side, it adheres to the WebRTC standard and on the SIP facing side, speaks SIP protocol.
To the core SIP platform, rtc.telnyx.com is merely another SIP UA. This is clearly illustrated by the fact that all methods of authenticating an SDK client are based on SIP connection.
This setup …
- avails WebRTC Voice SDKs the worldwide PSTN calling coverage and, more importantly,
- puts those calls under the umbrella of Programmable Voice API.
WebRTC Voice SDKs CANNOT be used on its own to orchestrate call flow
They merely allow some form of local control, e.g. un/hold, un/mute, sending DTMF digits. To orchestrate call flow or manipulate audio, TeXML or Call Control API must be used. Consider this example – a simple prepaid calling app where the user is told the remaining number of minutes before the call is placed. In the case of inadequate balance, they are told to top up before the call is hung up gracefully. The Voice SDKs are insufficient to achieve this simple call flow on their own. Instead, it is necessary to incorporate call control API —- The call leg instantiated by the SDK must be parked via a setting on the SIP connection.
- The user’s backend must
- respond to Telnyx webhooks,
- inject the necessary custom Text-To-Speach audio,
- place another outbound leg to the intended PSTN destination (or hangup due to insufficient balance), and finally,
- bridge the WebRTC call leg with the PSTN leg
WebRTC SDKs’ role in the Telnyx Voice Product Suite
To conclude, WebRTC SDKs’ role in the Telnyx voice product suite is one where- They bring the Telnyx voice infrastructure closer to the ultimate end users. Developers do not need to maintain their own voice infrastructure. Instead, they can focus on building user facing applications and business logic.
- They lower the barrier to access Telnyx’s worldwide PSTN coverage. Developers do not need to know SIP. Instead, they can work with the widely adopted WebRTC standardization and API.
- They unify all the crucial building blocks of a CPaaS platform under the Telnyx umbrella. Developers do not need to manage multiple integrations and vendors in their stack.
SDK Commonalities
Source: https://developers.telnyx.com/docs/voice/webrtc/sdk-commonalities.md
Classes, Methods, and Events
Broadly speaking, across all the SDKs — There are two main classes —- The Client class that represents the session. This session encapsulates the websocket connection which is used for signaling and the active call.
- The Call class that represents a webRTC media connection
- Instantiate an outbound call
- Un/Register callback handlers for events
- Control input and output devices
- Answer or hang up
- Emit DTMF digits
- On changes to the websocket, e.g. connected or disconnected
- On changes to the client, e.g. ready to make and receive calls
- On changes to the call, e.g. answered
Call States
Every SDK exposes a set of call states that describe where a call is in its lifecycle. The diagram below shows the common state machine shared across all WebRTC SDKs: Some platforms define additional states beyond the common set. iOS and Android add RECONNECTING and DROPPED (with an associated reason) for network-recovery scenarios. Flutter and Android add an ERROR state for unrecoverable failures.Authentication
A Client instance needs to be properly authenticated before a call can be made or received. The following means of authentications are offered Consult the linked guides on to the specific how-to guides.Dialing Registered Clients
Method of Authentication Dialing registered clients with Examples Basic credential based SIP connection SIP user name on the connection object john1234@sip.telnyx.com Basic credential based SIP connection Phone number on the connection (* See notes below.) +13128889999 Telephony credential SIP user name on the telephony credential object gencredXXXYYY@sip.telnyx.com JWT SIP user name on the parent telephony credential object gencredxXxYyY@sip.telnyx.com Dialing registered client using phone number on the connection requires “Destination Number Format” to be set as “SIP Username” on the “Inbound” setting of the same connection.Multi-client Registration Behavior
It’s recommended that the user sticks to one method of authentication and not mix and match unless there is a compelling use case for it. Here is an example to illustrate — Credential based SIP connection with SIP usernamejohn1234. Attached to this connections are:
- Telephony credential,
gencred1- JWT,
token1_1
- JWT,
- Telephony credential,
gencred2- JWT,
token2_1 - JWT,
token2_2
- JWT,
-
client_ais registered withjohn1234 -
client_bis registered withgencred1 -
client_cis registered withtoken1_1 -
client_dis registered withgencred2 -
client_eis registered withtoken2_1 -
client_fis registered withtoken2_2Dialing… Which client gets rung… john1234@sip.telnyx.com client_a gencred1@sip.telnyx.com Indeterminate; the last client to register between client_b and client_c. gencred2@sip.telnyx.com Indeterminate; the last client to register between client_d, client_e and client_f.
Common Usage Patterns
Two common primitive patterns are presented below. They can be augmented or used in combination with each other to achieve the user’s desired call flows.Pattern 1
This pattern is driven by the client-end application.- A client-end application (Web or Mobile App) initiates a call.
- The call is temporarily parked by Telnyx.
- Telnyx issues a webhook event to the user’s backend service.
- User’s backend service performs additional processing using Telnyx Voice API, TeXML or Conferencing API.
- Depending on user’s business logic,
- a second call leg may be initiated by the user’s backend and bridged to the initial call leg, or
- the initial call leg be put into a queue or conference until bridged to another call leg.
Pattern 2
This pattern is driven by a call from outside the Telnyx network.- Telnyx receives a call from outside the Telnyx network, e.g. PSTN.
- Telnyx processes the call via TeXML instruction or Voice API commands
- That call leg is placed into a queue or conference room
- User’s backend service initiates a second call leg toward a client-end application
- The two call legs are eventually joined via bridge command or conference join
Costs
WebRTC call legs are billed at $0.002/minute. Other voice legs and add on features are charged separately and independently according to the user’s price plan.Credential Connections
Source: https://developers.telnyx.com/docs/voice/webrtc/auth/credential-connections.md
Prerequisites
- A valid V2 API key
Creating a Credential Based SIP Connection
The following API request will create a basic credential based SIP connection.SDK Authentication
SDKs are authenticated withuser_namepassword
Limits
Sum of the following may not exceed 10,000 for an account.- Count of credential connection
- Count of IP connection
- Count of FQDN connection
- Count of external connection
- Count of TeXML application
- Count of Call Control Application
Additional Resources
Telephony Credentials
Source: https://developers.telnyx.com/docs/voice/webrtc/auth/telephony-credentials.md
Prerequisites
- An active credential based SIP connection
Create a Credential
The following API request will create a telephony credential.connection_idis requiredexpires_atis recommended for security especially when many are expected to be creatednameandtagare recommended for easy management
Updating a Credential
After a credential’s creation, it may be updated via the PATCH endpoint.expired credential since that state is terminal.
Revoking a Credential
A client-side application’s voice capabilities can be revoked by removing the corresponding credential.Managing Credentials
The following filters are useful when managing many credentials.filter[resource_id]e.g.filter[resource_id]=connection:1567510696929005999. Note thatconnection:must be prepended to the connection ID.filter[status]e.g.filter[status]=expiredfilter[status]e.g.filter[tag]=sandbox
SDK Authentication
SDKs are authenticated withsip_usernamewhich starts withgencredsip_password
Limits
Currently, there exists- No limit on count of telephony credentials on a connection,
- Nor any limit on the aggregate count of telephony credentials on a single account.
Additional Resources
JWTs
Source: https://developers.telnyx.com/docs/voice/webrtc/auth/jwt.md
Prerequisites
- An active telephony credential
Create a Token
The following API request will generate a JWT.- 24 hours after its creation or
- the parent telephony credential is expired
SDK Authentication
SDKs are authenticated with the JWT.Limits
Currently, there exists- No limit on count of tokens on a telephony credential,
- Nor any limit on the aggregate count of tokens on a single account.
Additional Resources
Overview
Source: https://developers.telnyx.com/docs/voice/webrtc/push-notifications.md
How push notifications work
When a client connects to the Telnyx WebRTC platform, it maintains a WebSocket connection that receives incoming call invitations in real time. If the app moves to the background or the device terminates it, that socket closes and calls can no longer reach the device. Push notifications bridge this gap. During login the SDK registers a platform-specific push token (FCM for Android, APNS for iOS) with Telnyx. When an incoming call targets that user, Telnyx sends a push notification through the appropriate service. The device wakes the app, which reconnects to the socket and receives the actual call invitation.Multidevice support
A single user can register up to 5 push tokens across iOS (APNS) and Android (FCM) devices. Each time a user logs in and provides a push token, Telnyx registers it. If a sixth token is added, the least-recently-used token is removed. This means up to five devices can receive push notifications for the same incoming call simultaneously.Platform setup
Push notification configuration has two parts:- Portal setup — Create a push credential in the Telnyx Portal and attach it to a SIP Connection.
- App setup — Integrate the push notification service into your application code and pass the token to the SDK on login.
API reference
You can also manage push credentials programmatically through the API:Android
Source: https://developers.telnyx.com/docs/voice/webrtc/push-notifications/android.md
Prerequisites
- A Telnyx account with a configured SIP Connection
- A Firebase project with Cloud Messaging enabled
- The Telnyx Android WebRTC SDK integrated into your application
Portal setup
1. Configure Firebase Cloud Messaging
- Go to the Firebase Console and open your project.
- Navigate to Project Overview → Project Settings → Service Accounts.
- Select Generate New Private Key to download a service account JSON file.
2. Create an Android push credential in the Telnyx Portal
- Go to portal.telnyx.com and log in.
- Navigate to API Keys in the left panel.
- Select the Credentials tab, then click Add → Android Credential.
- Enter a credential name and paste the contents of the service account JSON file into the Project Account JSON field.
- Click Add Push Credential to save.
3. Attach the credential to a SIP Connection
- Navigate to SIP Connections in the left panel.
- Open the SIP Connection you want to configure (or create a new one).
- Select the WebRTC tab.
- In the Android section, select the push credential you created.
- Save the SIP Connection.
App setup
Retrieve the FCM token
After integrating Firebase into your Android application (Firebase setup guide), retrieve the FCM registration token:Pass the token to the SDK
Provide the FCM token when connecting theTelnyxClient. The SDK registers it with Telnyx so push notifications can be routed to this device.
Handle incoming push notifications
Create aFirebaseMessagingService to process incoming FCM messages. Parse the metadata field from the notification payload and pass it to your notification UI:
Decline calls from push notifications
The SDK providesconnectWithDeclinePush() to decline incoming calls without fully reconnecting:
decline_push: true parameter, handles the decline, and disconnects automatically.
Android 14 permissions
Android 14 requires explicit notification permissions. Add these to yourAndroidManifest.xml:
POST_NOTIFICATIONS at runtime before showing notifications.
Troubleshooting
FCM token not passed to login
Verify that the FCM token is retrieved successfully and included in theCredentialConfig or TokenConfig passed to connect(). Check your logs for the token value.
Incorrect google-services.json
Confirm that thegoogle-services.json file is in your app module’s root directory and the package name matches your application.
Wrong push credential on the SIP Connection
In the Telnyx Portal, open your SIP Connection → WebRTC tab → Android section and verify the correct credential is selected.Invalid push credential
If the service account JSON is malformed or from the wrong Firebase project, push delivery fails silently. Generate a fresh key from the Firebase Console and update the credential in the Portal.Testing push delivery
The SDK repository includes a testing tool in thepush-notification-tool/ directory that sends test FCM notifications to verify your setup independently of the Telnyx call flow:
Next steps
- Push notifications overview — Multidevice support and architecture
- Android SDK reference — Full SDK documentation
- Mobile Push Credentials API — Manage credentials programmatically
iOS
Source: https://developers.telnyx.com/docs/voice/webrtc/push-notifications/ios.md
Prerequisites
- A Telnyx account with a configured SIP Connection
- An Apple Developer account
- The Telnyx iOS WebRTC SDK integrated into your application
Portal setup
1. Create a VoIP push certificate
For official Apple documentation, see Create VoIP Services Certificates. You will need:- An Apple Developer account
- Your app’s Bundle ID
- A Certificate Signing Request (CSR) from your Mac
- Go to developer.apple.com and sign in.
- Navigate to Certificates, Identifiers & Profiles.
- Click the + button to create a new certificate.
- Select VoIP Services Certificate and click Continue.
- Choose the Bundle ID for your application and click Continue.
- Upload a CSR file from your Mac.
- Open Keychain Access on your Mac.
- Go to Keychain Access → Certificate Assistant → Request a Certificate from a Certificate Authority.
- Enter your email address, select Save to disk, and click Continue.
voip_services.cer) and double-click it to install it in your Keychain.
A single VoIP Services Certificate works for both APNS sandbox and production environments. You need a separate certificate for each Bundle ID.
2. Export cert.pem and key.pem
- Open Keychain Access and search for “VoIP Services”.
- Verify the certificate is installed for your Bundle ID.
- Right-click the certificate and select Export. Save as a
.p12file (you’ll be prompted for a password). - Run the following commands to extract the PEM files:
3. Create an iOS push credential in the Telnyx Portal
- Go to portal.telnyx.com and log in.
- Navigate to API Keys in the left panel.
- Select the Credentials tab, then click Add → iOS Credential.
- Enter a credential name (using your Bundle ID makes it easy to identify).
- Paste the full contents of
cert.peminto the certificate field (include the-----BEGIN CERTIFICATE-----and-----END CERTIFICATE-----markers). - Paste the full contents of
key.peminto the key field (include the-----BEGIN RSA PRIVATE KEY-----and-----END RSA PRIVATE KEY-----markers). - Click Add Push Credential to save.
4. Attach the credential to a SIP Connection
- Navigate to SIP Connections in the left panel.
- Open the SIP Connection you want to configure (or create a new one).
- Select the WebRTC tab.
- In the iOS section, select the push credential you created.
- Save the SIP Connection.
App setup
Enable push notification capabilities
- Open your Xcode project.
- Select your app target in the Project Navigator.
- Go to Signing & Capabilities and click + Capability.
- Add Push Notifications.
- Add Background Modes and enable Voice over IP.
Configure PushKit
Import PushKit and register for VoIP push notifications:PKPushRegistryDelegate to capture the device token:
Pass the token to the SDK
Include the APNS device token when connecting theTelnyxClient:
Handle incoming VoIP push notifications
When a push notification arrives, reconnect the client and report the call to CallKit:Disable push notifications
To disable push notifications for the current user:Troubleshooting
VoIP certificate issues
- Verify your VoIP Services Certificate is not expired.
- Ensure the certificate matches the Bundle ID used in your app.
- For different Bundle IDs (e.g.,
com.myapp.devvscom.myapp), create separate certificates.
Push token not passed to login
Check that the APNS device token is captured inpushRegistry(_:didUpdate:for:) and included in TxConfig when calling connect().
Wrong credential on the SIP Connection
In the Telnyx Portal, open your SIP Connection → WebRTC tab → iOS section and verify the correct credential is selected.APNS environment mismatch
- Debug builds (Xcode): Use sandbox environment — set
pushEnvironmenttosandboxinTxConfig. - Release builds / TestFlight: Use production environment — set
pushEnvironmenttoproduction. - Ensure the APNS environment matches your build signing profile.
Testing push delivery
The SDK repository includes a testing tool in thepush-notification-tool/ directory:
cert.pem, key.pem, and the target APNS environment (sandbox or production).
Common error responses from the tool:
- BadDeviceToken: Token is invalid or expired
- BadCertificate: Certificate files are invalid or expired
- BadTopic: Bundle ID doesn’t match certificate
- TopicDisallowed: Certificate doesn’t have VoIP permissions
Next steps
- Push notifications overview — Multidevice support and architecture
- iOS SDK reference — Full SDK documentation
- Mobile Push Credentials API — Manage credentials programmatically
Flutter
Source: https://developers.telnyx.com/docs/voice/webrtc/push-notifications/flutter.md
Prerequisites
- A Telnyx account with a configured SIP Connection
- The Telnyx Flutter Voice SDK integrated into your application
- Android: A Firebase project with Cloud Messaging enabled
- iOS: An Apple Developer account with a VoIP push certificate
Portal setup
Flutter apps are cross-platform, so you need credentials for each platform you target:- Android: Follow the Android portal setup to create an Android push credential using your Firebase service account JSON.
- iOS: Follow the iOS portal setup to create an iOS push credential using your VoIP certificate PEM files.
App setup
Android — Firebase Cloud Messaging
1. Listen for background push notifications
Register a background message handler in yourmain method:
2. Handle the push notification
Process the incoming message and show a call notification using a plugin like FlutterCallkitIncoming:3. Create a high-importance notification channel (Android 8.0+)
For Android 8.0 and higher, create a dedicated notification channel so incoming call notifications display as heads-up alerts. Use the flutter_local_notifications package to configure the channel with maximum importance.iOS — Apple Push Notification Service
For iOS, the Flutter SDK uses APNS through the native PushKit integration. Configure your iOS project following the standard iOS app setup, which includes:- Enabling Push Notifications and Background Modes (VoIP) capabilities in Xcode.
- Configuring PushKit to register for VoIP pushes.
- Reporting incoming calls to CallKit (required on iOS 13+).
Troubleshooting
Android-specific issues
- FCM token not received: Ensure
Firebase.initializeApp()is called before requesting the token and thatgoogle-services.jsonis correctly placed. - Notifications not showing in background: Verify your background handler is annotated with
@pragma('vm:entry-point')and registered viaFirebaseMessaging.onBackgroundMessage. - Low-priority notifications: Create a notification channel with
Importance.maxfor incoming call alerts.
iOS-specific issues
- No push notifications: Confirm the VoIP push certificate matches your Bundle ID and is uploaded to the Telnyx Portal.
- App terminated on push: On iOS 13+, you must report every VoIP push to CallKit or the system kills your app.
- Environment mismatch: Use sandbox for debug builds and production for release/TestFlight builds.
General
- Push works but no call invitation: The push notification only signals that a call is incoming. Your app must reconnect to the TelnyxClient socket after receiving the push so the actual invitation can be delivered.
- Multidevice: A user can register up to 5 push tokens. If a 6th is added, the oldest is removed.
Next steps
- Push notifications overview — Multidevice support and architecture
- Flutter SDK reference — Full SDK documentation
- Mobile Push Credentials API — Manage credentials programmatically
React Native
Source: https://developers.telnyx.com/docs/voice/webrtc/push-notifications/react-native.md
Prerequisites
- A Telnyx account with a configured SIP Connection
- The
@telnyx/react-voice-commons-sdkintegrated into your application - Android: A Firebase project with Cloud Messaging enabled
- iOS: An Apple Developer account with a VoIP push certificate
Portal setup
React Native apps are cross-platform, so you need credentials for each platform you target:- Android: Follow the Android portal setup to create an Android push credential using your Firebase service account JSON.
- iOS: Follow the iOS portal setup to create an iOS push credential using your VoIP certificate PEM files.
App setup
Install dependencies
Android — Firebase Cloud Messaging
1. Add the Firebase configuration file
Downloadgoogle-services.json from your Firebase project console and place it in your project root (same level as package.json):
2. Configure the Android manifest
Add the Firebase messaging service and Telnyx notification receiver toandroid/app/src/main/AndroidManifest.xml:
3. Retrieve the FCM token
The SDK handles FCM token retrieval internally on Android. Pass the token to the SDK when connecting:iOS — Apple Push Notification Service
1. Configure PushKit
Use thereact-native-voip-push-notification package to register for VoIP pushes and capture the device token:
2. Enable capabilities in Xcode
- Open your iOS project in Xcode.
- Go to Signing & Capabilities.
- Add Push Notifications.
- Add Background Modes and enable Voice over IP.
Troubleshooting
Android-specific issues
- FCM token not received: Verify
google-services.jsonis in the correct location and the package name matches your app. - No notifications in background: Ensure the Firebase messaging service is declared in your Android manifest.
- Wrong credential on SIP Connection: Check the Telnyx Portal → SIP Connection → WebRTC → Android section.
iOS-specific issues
- No push notifications: Confirm the VoIP push certificate matches your Bundle ID and is uploaded to the Telnyx Portal.
- App terminated on push: Report every VoIP push to CallKit on iOS 13+.
- Environment mismatch: Use sandbox for debug builds and production for release/TestFlight.
General
- Push works but no call invitation: The push notification signals an incoming call. Your app must reconnect to the socket after receiving the push so the SDK can receive the actual invitation.
- Multidevice: A user can register up to 5 push tokens across iOS and Android devices.
Next steps
- Push notifications overview — Multidevice support and architecture
- React Native SDK reference — Full SDK documentation
- Mobile Push Credentials API — Manage credentials programmatically
JS SDK Demo App
Source: https://developers.telnyx.com/docs/voice/webrtc/js-sdk/demo-app.mdTo lower onboarding barrier, a JS SDK demo app was built and made accessible at webrtc.telnyx.com. To use it, complete the following procedure. Instead of portal.telnyx.com screenshots being displayed, only API requests are presented, as frequent UI improvements render this page out of date.
Pre-req 1: Account Balance
Sign up and top up the account with a small amount of credit, e.g. $5.Pre-req 2: Outbound Voice Profile (OVP)
Pre-req 3: Credential Based SIP Connection
outbound_voice_profile_id is the id returned in the previous API request.
Pre-req 4: Phone Number
For ease of activation, choose US or CA phone numbers as there exists no regulatory requirements for their immediate use.connection_id from the previous step.
pending in the immediate response. After a short wait, poll the order status.
status is success before proceeding.
Setting Up and Using the Demo App
Follow this instruction to create a telephony credential. The demo app should have the following configuration- “Authentication” → “Credential”
- “SIP Username” → from telephony credential
- “Password” → from telephony credential
- “Caller ID Name” → purchased phone number in +E164 format
- “Caller ID Number” → purchased phone number in +E164 format
registered in the log to the right.
Making Call
To make an outbound call, put the destination phone number in +E164 format. Ensure the destination country is in thewhitelisted_destinations of the configured OVP.
Receiving Call
Open another tab and successfully register another client. From that client, dial[xxx]@sip.telnyx.com where xxx is the sip_username of the telephony credential of the first client. It starts with gencred.

Additional Resources
- Anatomy of the JS SDK.
- OVP API Reference
- Credential Based Connection API Reference
- Number Searching API Reference
- Number Order API Reference
JS SDK Anatomy
Source: https://developers.telnyx.com/docs/voice/webrtc/js-sdk/anatomy.mdWhile some differences exist between the JS SDK and the mobile SDKs, they follow a similar client lifecycle and call flow. The JS SDK demo app is used here as it’s far easier to set up the application (just load up webrtc.telnyx.com) and perform debugging using browser tooling.
Overview
The SDK does two main things:- Establishes an active websocket connection to send and receive signaling messages to and from rtc.telnyx.com.
- Establishes a media session for a call
Client Instantiation & Authentication
- Go to webrtc.telnyx.com
- Right click; Inspect; Select Network tab and filter WS traffic
- Follow this page to successfully register the demo app.

- creates a session object and
- registers handlers for all 4 socket events
connect method on the SDK client …
- Initiates a WebSocket connection to rtc.telnyx.com
- Once the socket is open, the login message is sent to rtc.telnyx.com.
- A
telnyx_rtc.clientReadyevent from rtc.telnyx.com triggers atelnyx_rtc.gateStatequery from the SDK client - A
REGEDevent from rtc.telnyx.com bubbles up astelnyx.ready.
Call Initiation
- In another tab, open chrome://webrtc-internals/
- Fill in “Call destination” with +18008648331 (United Airlines IVR)
- Click “Call”

RTCPeerConnectionis instantiated.getUserMediais invoked to obtain user’s permission for audio and eventually theMediaStream
addTransceiveris invoked to add the local stream to the sender of theRTCPeerConnection.
- The previous step triggers the
negotiationneededevent.
- In the event handler, the SDK invokes
createOffer.
- This API call will eventually create a
RTCSessionDescriptionwith information on the local media stream.
- The SDK will then invoke the
setLocalDescriptionto set the SDP of the client peer.
- Concurrently,
createOfferalso kicks off the ICE candidate gathering.
- When all is done,
icecandidateevent triggers withcandidate = nullto indicate the process is completed. Subsequently, the existing local SDP parameters are augmented with the ICE candidates. - At this point, all necessary info are present to send the invite to rtc.telnyx.com.
- As a result, on the websocket, Message #1 through #4 are observed.
- At Message #5, rtc.telnyx.com sends over its SDP in the
telnyx_rtc.mediaevents. - Upon receipt of this message, the SDK invokes
setRemoteDescriptionto set the SDP of the remote peer.
- Finally, two peers of the
RTCPeerConnectionare fully identified. connectionState changes from connecting to connected.
- Media will flow over UDP.
Contact Center (CCaaS)
Source: https://developers.telnyx.com/docs/voice/webrtc/use-cases/contact-center.md
Overview
In building a Contact Center as a Service solution leveraging Telnyx WebRTC, enable SIP connection credentials with Park Outbound Calls and webhook events for enhanced functionality and seamless communication flows.Key features
Webhook events- Monitor SIP connection events in real-time.
- Receive notifications for call events: dialing, answering, bridging, hang-up, voicemail completion.
- Primary/failover URL configuration for reliability.
- Temporarily hold calls until further instructions via Voice API.
- Enable additional processing or decision-making before connecting.
- Provide customizable call handling experiences.
- Utilize Telnyx’s call control capabilities (Voice API documentation).
- Issue commands based on webhook events: answer, play audio, bridge, transfer.
- Handle sophisticated workflows for call routing.
Inbound call flow
- User calls main number, answered with text-to-speech greeting.
- IVR menu presents options to mark call attributes (language, skills, department).
- Call transferred to queue, parked while waiting for agent.
- Auto-transfer to most idle agent or manual cherry-picking.
- Call recording initiated when agent answers.
- Call forwarded to multiple agents simultaneously with recording enabled.
- Additional call control: mute, hold, transcription, text-to-speech announcements.
Frontend implementation
Authentication
Agent desktop applications should have an authentication process implemented. We recommend using authentication tokens generated from individual telephony credentials created for each agent. When an agent logs in, the frontend app requests an authentication token from the backend, which is then used for subsequent API requests in the WebRTC client. When a call is received, you can see which agents are logged in with the on-demand generated credentials. Your call center service would use our Call Control API to dial each of the generated credentials to connect the caller with one of the available agents. Once agents are logged in, make sure your WebRTC client informs your call center backend that the agents are registered. This ensures the backend has a list of agents it can dial each time an inbound call is received to the main number. See more details in the User authentication section in the Backend implementation for the Voice API methods to be used on the backend side.Agent desktop application
Agent desktop application should support the following options: Agent status management: The agent should be able to report their current status, such as Available or Unavailable, so the backend application can see the currently available agents and decide which agent should receive the next call. Here is an example softphone application (WebRTC client) with an option to choose a preferred audio device.


Audio device settings
Get a list of available audio devices:Call control toolbar
Toggle microphone:Backend implementation
The backend application handles call routing, IVR logic, and agent management through Telnyx Voice API webhooks.User authentication
For each user, generate on-demand telephony credentials which should be stored in a database and associated with the user login. Agent desktop application should request an authentication token to be created based on the telephony credentials. Generate on-demand telephony credentials On-Demand Credentials help you onboard new customers or team members under your SIP connection, allowing you to separate each user with their own security credentials. This solution is ideal for integrating WebRTC into your own platforms, enabling your backend system to create outbound calls to each on-demand generated credential. You can use the optional parameterexpires_at if you would like to set an expiration time for the credentials.
Call flow
In the backend application, we can fully control the call flow from the initiation of the call up to the call disconnect event. Based on the webhook notification, we can decide what kind of actions should be applied to the call. To monitor the call and proceed with the call flow, we should monitor call event types received on the webhook URL. Having an integration with the CRM application, we can retrieve caller data, for instance based on the caller number:call.initiated webhook, you should answer the call and provide an initial greeting with IVR options using the speak option:
Next steps
- Review WebRTC authentication options.
- Explore Call Control API documentation.
- Learn more about webhook fundamentals.
Outbound Dialer
Source: https://developers.telnyx.com/docs/voice/webrtc/use-cases/outbound-dialer.mdBuild an automated outbound dialer system that enables agents to make high-volume outbound calls efficiently using Telnyx WebRTC and Call Control API.
Overview
In building an outbound dialer solution leveraging Telnyx WebRTC, enable SIP connection credentials with Park Outbound Calls and webhook events to combine front-end WebRTC functionality with backend voice application.Key features
Park Outbound Calls- Combine front-end WebRTC application with backend voice application using Telnyx Voice APIs.
- Enable advanced call flow control and routing.
- Learn more about Park Outbound Calls.
- Monitor SIP connection events in real-time.
- Receive notifications for call events: dialing, answering, bridging, hang-up, voicemail completion.
- Primary/failover URL configuration for reliability.
Required components
- WebRTC Client.
- Backend Server Application.
- SIP Connection with Park Outbound Calls Enabled (select TeXML option when using the TeXML approach).
Frontend implementation
In a typical front-end WebRTC application, there are many components that should be supported. Agent status management: The outbound dialer application should be able to display the agent’s current status, such as, but not limited to, Available, Unavailable, Busy, and Offline. This type of management should not only act as an indicator for other agents but also limit agents’ ability to transfer calls to unavailable agents. This status should also be correlated with the WebRTC client state. This means that when an agent’s status is set to available, the WebRTC client should be fully registered and ready to place outbound calls. This should be handled at a global level, typically using state management frameworks such as Global Context APIs or Redux. Here is an example softphone application (WebRTC client) with an option to change its current state.

Backend implementation
The backend implementation is a crucial component of a successful call. The following sequence diagram covers a typical outbound call flow using Telnyx Voice API. Below the sequence diagram, I describe each step.
1. Client Registers with Telnyx
The process starts with the WebRTC client (the Front End App) connecting to Telnyx by sending aClient.connect (Register) request. This is essentially the WebRTC client registering with Telnyx to initiate communications.
2. Initiating a Call
Once the WebRTC client is connected, it requests to initiate a call by sending aClient.newCall(destinationNumber,callerNumber) method to Telnyx. The request requires the destination number and the caller number. This request is routed from the front-end WebRTC client application to the back-end server application, which acts as the intermediary between the client and Telnyx for controlling call logic.
3. Dialing PSTN (command)
The backend server then instructs Telnyx to dial the destination number in the PSTN using theDial PSTN with Dial Command. This command triggers Telnyx to initiate an outbound call to the PSTN.
4. Call Initiated (webhook)
Telnyx acknowledges the initiation of the call process by triggering acall.initiated webhook to the backend server. This webhook indicates that the call process has started but does not necessarily mean the call has been answered.
5. PSTN Outbound Call
Telnyx makes the outbound call to the destination number in the PSTN network.6. PSTN Answered (webhook)
When the PSTN destination answers the call, Telnyx sends a notification back to the backend server through acall.answered webhook, indicating that the call had been successfully answered on the PSTN side.
7. Bridging Call Legs (command)
After the call is answered, the next step is to bridge the call between the WebRTC client and the PSTN to enable two-way communication. The backend server sends a Bridge Call Legs:call.bridge(call_control_id) command to Telnyx, instructing it to connect the two call legs.
8. Call Bridged (webhook)
Once the call legs are successfully bridged, Telnyx triggers acall.bridged webhook to the backend server, indicating that the WebRTC agent and the PSTN call are now connected, and the call is in progress.
9. Call In Progress
With the bridge established, the WebRTC agent (the user on the front-end client) and the PSTN participant can now communicate. This state continues until either party terminates the call. If the call is ended, Telnyx triggers acall.hangup webhook. An example call.hangup event is provided below.

1. Client Registers with Telnyx
The process starts with the WebRTC client (the Front End App) connecting to Telnyx by sending aClient.connect (Register) request. This is essentially the WebRTC client registering with Telnyx to initiate communications.
2. Initiating a Call
Once the WebRTC client is connected, it requests to initiate a call by sending aClient.newCall(destinationNumber,callerNumber) method to Telnyx. The request requires the destination number and the caller number. This request is routed from the front-end WebRTC client application to the back-end server application, which acts as the intermediary between the client and Telnyx for controlling call logic.
3. Dialing PSTN (command)
The backend server then instructs Telnyx to dial the first destination number. This command triggers Telnyx to initiate an outbound call to the PSTN.4. TeXML Dial Verb
The Url parameter hits a server that then instructs Telnyx using XML to dial the second PSTN transfer B-leg. The verb triggers Telnyx to initiate an outbound call to the second PSTN leg.Next steps
- Review WebRTC authentication options.
- Explore Call Control API documentation.
- Learn more about webhook fundamentals.
Call Detail Records
Source: https://developers.telnyx.com/docs/voice/webrtc/troubleshooting/detail-records.md
Searching for Records
Every call between a voice SDK client and Telnyx produces awebrtc detail record. They can be searched via this API.
For example, the following query returns webrtc detail records of calls made
- to/from any clients registered with
myagent01username - within
today
Interpreting Records
While most of the fields in the records are self explanatory, the following parameters are given additional exposition.IDs in the WebRTC Domain
session_ididentifies a session, i.e. a successful registration, between an SDK client and Telnyx.call_id- identifies a call between an SDK client and Telnyx
- can be generated by the SDK client or Telnyx
- has a many-to-one relationship to a session, i.e. a session can have many calls.
call_id is essential to locate the debug log produced by an SDK client. This is further explained here.
IDs in the SIP Domain
The following IDs can be used to identify the SIP leg of a voice SDK call.telnyx_leg_idtelnyx_session_idfs_channel_id
IDs in the Programmable Voice Domain
If programmable voice (call control or TeXML) is used in the call flow, e.g. parking the outbound webRTC call, the following ID may also be returned in the detail record.telnyx_call_control_id
Debug Logs
Source: https://developers.telnyx.com/docs/voice/webrtc/troubleshooting/debug-logs.mdThis is a beta feature. The data schema and/or presentation may change without notice. Debug data is collected on the SDK client. It provides empirical data on the call leg between SDK client and Telnyx.
Availability
Enabling Debug
Initialize the SDK client with debug set totrue and output set to socket.
Locating the Debug Data
When properly enabled, the SDK client will ship debug data frames to Telnyx over the websocket. The data frames are assembled into a singlejson file and stored in a Telnyx Cloud Storage bucket located in us-central-1 belonging to the user.
The bucket is named voice-sdk-debug-reports-[USER-ID] where USER-ID is the user’s account ID.
The objects are named following this schema [call_id]/rtc_stats_reports/[segment_id] where call_id is the ID identifying the call leg between the SDK client and Telnyx. In most cases, there is only one data segment. When there is a reconnect between the SDK client and Telnyx, there may be more than one data segment.
To illustrate the above point more concretely, consider this example:
- A call is made from a JS SDK client to a phone number.
- The WebRTC call record is located using the detail record API.
- Noting the
call_id, locate the data using Telnyx Mission Control portal or a properly configured AWS CLI.
prefix is the call_id.
Visualizing the Data
The data can be uploaded and visualized via https://webrtc-debug.telnyx.com/.
Interpreting the Data
The next section provides addition information on how to use the data to diagnose user issues.Interpreting Debug Data
Source: https://developers.telnyx.com/docs/voice/webrtc/troubleshooting/interpreting-debug-data.mdThis is a beta feature with limited availability by SDK type. Data schema and/or presentation may change without notification. To make full use of this guide, the reader is encouraged to complete the following steps in order to have a real world example to follow along.
- Initiates an outbound call from a properly configured
https://webrtc.telnyx.com/with debug enabled and data sent over socket. - Locate the debug data.
- Upload the data to
https://webrtc-debug.telnyx.com/.
Peer Configuration

prefetchIceCandidates is disabled, the pool size is set to 0. Otherwise, it’s set to 255.
If forceRelayCandidate is enabled, then transport policy will be set to relay.
Lastly, by default, Telnyx SDKs use the following endpoints to gather ICE candidates.
stun.l.google.comstun.telnyx.comturn.telnyx.com
ICE Candidates & Candidate Pair

remote-candidate of host type offered. This represents the Telnyx’s end of the peer connection.
There will always be multiple local-candidate offered unless relay candidate was configured to be used.
For a call to be successfully established, at least one local-candidate of the following type must be present:
prflxsrflxrelay
host candidate type cannot be used to establish peer connection over the internet.
If no viable local-candidate are present, it’s highly likely that the SDK client is located on a very restrictive network where all UDP traffic is blocked and access to certain endpoints (turn.telnyx.com) are not allowed.
Barring that, there will be one pair of ICE candidates used for this call.

RTT

Packets Lost
A high packet lost value provides clues to skipped audio.
Jitter
A high jitter value provides clues to inconsistent audio quality throughout the call.
Other Useful Data
If the user is experiencing one way audio, it’s worth checking inbound and outbound audio level to corroborate the user’s claim.WebRTC JS SDK quickstart
Source: https://developers.telnyx.com/development/webrtc/js-sdk/tutorials/make-your-first-call.md
Quickstart
Get the Telnyx WebRTC JS SDK running in your app — make your first call in under 5 minutes.Before You Begin
You’ll need:- A Telnyx account
- Node.js 16+ or a modern browser
Portal Setup
Set up everything you need in the Telnyx Portal — no API calls required. 1. Buy a number Go to Numbers → Buy Numbers in the Portal. Purchase a number in your desired country and area code. 2. Create a Credential Connection Go to Call Connections → Create → SIP Credential Connection. This defines how your WebRTC client authenticates with the SIP network. Give it a name and keep the defaults. 3. Create a Telephony Credential Go to Call Connections → [Your Connection] → Credentials → Create. Each user (or device) needs its own credential. Note the username and password — you’ll use these to generate a JWT. 4. Assign your number to the connection Go to Numbers → Your Numbers, select your number, and assign it to the Credential Connection you created. 5. Generate a JWT Still in the Credentials section, click Generate Token for the credential you created. Copy the JWT — this is what you’ll pass to the SDK aslogin_token.
For production, generate JWTs from your backend using the API. See Authenticating Your App for the full flow.
Install
Create a Client
The SDK connects to Telnyx via WebSocket and establishes WebRTC media sessions. Here’s the minimal setup:telnyx.ready before making calls. The client needs to establish a WebSocket connection and authenticate before it can place calls.
Authentication
The SDK supports three authentication methods:
JWT (Production):
Make an Outbound Call
Receive an Inbound Call
Play Audio
The SDK handles audio elements automatically, but you can provide your own:Handle Errors
Disconnect
Always disconnect when the user leaves or the app unloads:Next Steps
- Authentication — JWT generation, token refresh, security best practices
- Call State Machine — Understanding call lifecycle and state transitions
- Call Options — Custom headers, ICE config, media control
- Error Handling — Structured error codes and recovery
- Best Practices — Production checklist, performance, security
- Demo App — Full working reference application
Quick Reference
Build a Call Center Agent
Source: https://developers.telnyx.com/development/webrtc/js-sdk/tutorials/build-call-center-agent.md
Build a Call Center Agent
This tutorial walks you through building a fully functional call center agent interface. You’ll learn how to answer incoming calls, mute/unmute, and place calls on hold — the basics a real agent needs. Prerequisites:- Completed Make Your First Call
- A Telnyx account with a Credential Connection and JWT set up
- A phone number routed to your Credential Connection
- Receives incoming calls
- Shows caller ID
- Supports mute and hold
- Tracks call duration
-
Handles multiple calls with hold/resume
This SDK is client-side only. The WebRTC JS SDK handles real-time audio in the browser — it connects agents to calls, manages call state, and streams media. To route calls, create dial plans, or implement IVR logic, you need a backend application using:
- Programmable Voice (Call Control) — Build server-side call flows with the Telnyx API. Create calls, transfer, bridge, and play audio programmatically.
- TeXML — Telnyx’s markup language for voice applications. Define call flows in XML with verbs for dial, gather, play, say, and more.
Step 1: Set Up the HTML
Createagent.html:
Step 2: Connect and Authenticate
Add a “ tag and connect:Step 3: Handle Incoming Calls
Step 4: Answer and Reject
Step 5: Call Controls
Step 6: Render the Active Calls UI
Step 7: Call Timer
Step 8: Cleanup
What’s Next?
You now have a working call center agent interface. Here are ways to extend it: Client-side (this SDK):
Server-side (backend):
See Also
- Make Your First Call — Basic tutorial
- Programmable Voice — Server-side call management
- TeXML — XML-based voice applications
- Production Best Practices — Deployment guide
WebRTC JS SDK authentication
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/authenticating-your-app.md
Authentication
The Telnyx WebRTC SDK supports three authentication methods. Use JWT for all production applications.Overview
Use JWT (
login_token) for all production applications. Credentials (login + password) are long-lived with no automatic rotation. JWTs expire after 24 hours and can be refreshed via TOKEN_EXPIRING_SOON.
Method 1: JWT (Recommended)
JWT is the most secure authentication method. You generate a short-lived token on your backend and pass it to the SDK.How It Works
Step 1: Create a Credential Connection
Create a SIP Credential Connection in the Telnyx Portal or via API:Step 2: Create a Telephony Credential
Each user needs their own credential. Never share one credential across multiple users.Step 3: Generate a JWT
Generate the JWT on your backend — never on the client. This requires your API key.Step 4: Use JWT in the SDK
Token Refresh
JWTs expire after 24 hours. Handle theTOKEN_EXPIRING_SOON warning to refresh without dropping the connection:
TOKEN_EXPIRING_SOON warning fires ~1 hour before expiration.
Method 2: Credential (Development Only)
Uselogin + password for local development and testing only.
- Local development and testing
- Quick prototyping before setting up JWT infrastructure
- Production applications
- Multi-user scenarios where each user needs their own identity
- Any environment where you need automatic token rotation
login value is the sip_username from a Telephony Credential (e.g., gencrednb4ADiBVjsvgvxem0OwkeNfryiIwhaUSJMJXjiwY3Y). The password is set when creating the credential.
Method 3: Anonymous (AI Assistants)
Connect to an AI assistant without requiring a credential. Theanonymous_login option accepts an object specifying the target:
- Click-to-call widgets connecting users directly to an AI assistant
- Embedding voice AI in web apps without managing credentials
- Cannot receive inbound calls
- No SIP identity — calls are outbound to the specified AI assistant only
- Limited call control features
Continue a conversation
Pass aconversation_id to resume an existing conversation with the AI assistant:
Credential Hierarchy
Understanding how Telnyx auth resources relate to each other:- Credential Connection — SIP-level configuration (transport, codecs, webhook)
- Telephony Credential — Individual identity (one per user)
- JWT — Short-lived token generated from a credential
Common Mistakes
Server-Side Token Generation
Here’s a complete Node.js/Express endpoint for generating JWTs:See Also
- IClientOptions — Full client configuration
- Quickstart — Get started in 5 minutes
- Credential Connections API — Create connections via API
- Telephony Credentials API — Manage credentials via API
- Create Access Token API — Generate JWTs via API
- Best Practices — Security best practices
Network Connectivity Requirements
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/configure-network-firewall.md
Network Connectivity Requirements
For the Telnyx WebRTC JS SDK to function properly, the client must be able to reach Telnyx’s signaling and media infrastructure.Overview
The SDK requires connectivity to three types of endpoints:Signaling
The SDK uses a persistent WebSocket connection for call signaling (invite, answer, hangup, etc.).
Requirements:
- Outbound WebSocket connections must be allowed on port 443
- No HTTP long-polling fallback — WebSocket is required
- Connection must remain open for the duration of the session
env property, but this is not recommended for production.
STUN
STUN servers help the client discover its public IP address for ICE negotiation.
The SDK automatically uses these STUN servers. No configuration required.
TURN
TURN servers relay media when direct peer-to-peer connectivity is not possible (e.g., symmetric NAT, restrictive firewalls).
The SDK automatically provisions TURN credentials. No manual configuration required.
UDP vs TCP vs TURNS/443:
- UDP (preferred) — Lower latency, better for real-time audio
- TCP (fallback) — Higher latency, used when UDP is blocked
- TURNS over 443 (last resort) — TURN over TLS on port 443, used when both UDP and TCP/3478 are blocked by restrictive firewalls or proxies
turns:turn2.telnyx.com:443) in addition to the existing TURN UDP/3478 and TCP/3478 entries. This provides a last-resort relay fallback for networks that block both UDP/3478 and TCP/3478 but allow outbound TCP/443.
Firewall Configuration
Minimum required rules
Optional but recommended
Media ports
RTP media uses dynamic ports allocated by the browser. These are ephemeral and cannot be whitelisted by port number. Instead:- Ensure TURN is accessible — TURN handles media relay when direct connectivity fails
- Allow UDP outbound to Telnyx media servers (the
remote_media_ipseen in SDP) - Don’t restrict outbound UDP to specific ports — this will break WebRTC
Restrictive Network Scenarios
STUN fails (error 701)
Symptom: Client cannot discover its public IP. Nosrflx or prflx ICE candidates.
Fix:
- Check firewall allows UDP to
stun.telnyx.com:3478 - If STUN is blocked, TURN may still work — the SDK falls back automatically
- If both STUN and TURN are blocked, calls cannot connect
TURN fails
Symptom: Client is on a restrictive network (symmetric NAT), can’t getrelay candidates.
Fix:
- Check firewall allows UDP to
turn.telnyx.com:3478 - If UDP is blocked, check firewall allows TCP to
turn.telnyx.com:3478 - If both UDP/3478 and TCP/3478 are blocked, TURNS over TLS on port 443 to
turn2.telnyx.comwill work — this is included in the default ICE server list since SDK v2.27.4 - If all TURN paths are blocked, use
forceRelayCandidate: trueto skip direct connectivity attempts:
Custom ICE servers with TELNYX_ICE_SERVERS
Starting with SDK v2.27.4, the SDK exports a public TELNYX_ICE_SERVERS catalog of ready-to-use ICE server entries. Import it and compose any combination into the iceServers option to override the defaults:
When you omit
iceServers, the SDK uses its built-in defaults (DEFAULT_PROD_ICE_SERVERS) which include STUN + TURN UDP/3478 + TURN TCP/3478 + TURNS/443. Providing an explicit iceServers array replaces the defaults entirely.
Corporate VPN
Symptom: Calls fail or have poor quality through VPN. Fix:- Whitelist
rtc.telnyx.com,stun.telnyx.com,turn.telnyx.com, andturn2.telnyx.comin VPN split-tunneling config - Ensure VPN doesn’t block UDP traffic to TURN servers or TLS to
turn2.telnyx.com:443 - Consider split-tunneling so WebRTC traffic bypasses the VPN
Docker / Container environments
Symptom: STUN errors, no ICE candidates, one-way audio. Fix:- Docker’s default bridge network (
172.xor10.x) can interfere with ICE candidate gathering - Use
--network hostmode for the container - Or configure the Docker network to use the host’s network stack
Testing Connectivity
Quick test
Open your browser’s DevTools console and run:Debug tools
- SDK debug mode: Set
debug: trueanddebugOutput: 'socket'in IClientOptions - Debug visualizer: Upload debug data to
https://webrtc-debug.telnyx.com/ - Call reports: Enable
enableCallReports: truefor programmatic access to ICE stats
Bandwidth Requirements
Recommended minimum bandwidth per call:
- Audio only: 100 kbps (including overhead)
- With video: 500-2000 kbps depending on resolution
See Also
- IClientOptions — ICE and network configuration
- Debug Data & Call Quality Analysis — Interpreting ICE and quality data
- Best Practices — Production deployment guide
- Error Handling — ICE and WebSocket error codes
Device Management
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/switch-audio-devices.md
Device Management
The Telnyx WebRTC JS SDK uses the browser’sMediaDevices API for audio device management. This guide covers selecting devices, switching mid-call, and handling permission changes.
Enumerate Devices
List available audio input and output devices:label is an empty string and deviceId is a placeholder.
Request Permissions
Before you can select a specific device, the user must grant microphone access:Select a Specific Device
When placing a call
Via ICallOptions constraints
Switch Devices Mid-Call
Replace the audio track on an active PeerConnection:replaceTrack() doesn’t require renegotiation — the switch is seamless. The remote party won’t hear a gap.
Speaker Output
Set the audio output device (sink) on the audio element:setSinkId() is not supported in all browsers. Safari does not support it as of 2026. Check typeof audioElement.sinkId !== 'undefined' before using.
Device Change Detection
Listen for device changes (headphones plugged in, Bluetooth connected, etc.):- Headphones plugged in → switch output to headphones
- Bluetooth headset disconnected → fall back to built-in speaker
- USB microphone connected → update device list
Mute vs Device Off
Don’t confuse muting with device management:Common Issues
”Device not found” after permission grant
Cause: The device list was cached before permission was granted. Labels and real device IDs are only available aftergetUserMedia().
Fix: Re-enumerate devices after permission is granted:
Echo or feedback
Cause: Speaker output is being picked up by the microphone (especially with built-in speakers + mic on laptops). Fix:- Use echo cancellation (enabled by default in most browsers)
- Recommend headphones for long calls
- Use
call.muteAudio()when not speaking
Device disappears mid-call
Cause: Bluetooth disconnected, USB device unplugged. Fix:- Listen for
devicechangeevents - Fall back to the default device:
See Also
- Call Class —
muteAudio(),unmuteAudio() - ICallOptions —
localStreamfor custom device selection - Best Practices — Production deployment guide
Manage Multiple Calls
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/manage-multiple-calls.md
Manage Multiple Calls
The Telnyx WebRTC JS SDK supports multiple simultaneous calls within a singleTelnyxRTC client session. This guide covers concurrent call management, per-call media elements, call waiting, hold/transfer patterns, and the warnings the SDK emits when multiple calls are active.
The SDK does not recommend having multiple active calls simultaneously and cannot guarantee stable behavior in all scenarios. The supported pattern is accepting and holding an inbound call while finishing an active one — the SDK handles this well. Running two fully active calls at the same time (both with bidirectional audio) is not recommended and may produce unpredictable media or signaling behavior.
Overview
A singleTelnyxRTC instance connected to rtc.telnyx.com can have multiple active calls at the same time. Each call has its own:
- Call ID (
call.id) — unique per call leg - Direction (
call.direction) —inboundoroutbound - State (
call.state) —ringing,trying,active,held,hangup,destroyed - PeerConnection — independent
RTCPeerConnectionper call - Media element —
remoteElement/localElement(see Per-call media elements)
Per-call media elements
Starting with SDK v2.27.4, you can assign a distinctremoteElement (and localElement) per call. This is essential for concurrent calls — without it, all calls share the same audio element and the SDK emits a SHARED_REMOTE_ELEMENT_OVERWRITE warning when a second call overwrites the first call’s stream.
Why per-call elements matter
Outbound calls
PassremoteElement at call creation:
Inbound calls
PassremoteElement when answering:
Backward compatibility
Omitting the per-call params keeps the session-levelclient.remoteElement as the fallback default. This is backward compatible with existing single-call integrations — no changes are needed for apps that handle only one call at a time.
Call waiting
When a second inbound call arrives while a call is already active, the SDK emits aMULTIPLE_ACTIVE_CALLS_DETECTED warning (33010). This is diagnostic only — the SDK does not block the second call.
Accept the second call
Reject the second call
Hold and switch between calls
Usehold() and unhold() to switch between concurrent calls:
hold() sends a re-INVITE to the remote party to pause media. The call stays in the held state and can be resumed with unhold().
Warnings for multiple calls
See Error Handling for the full warning reference.
Transfer
Blind transfer and attended transfer work with multiple calls. To perform an attended transfer:Server-dialed consult leg (auto-answered second inbound call)
Some attended-transfer and consult flows are driven from the server: while the agent is on their customer call, Call Control dials the agent’s own credential as a second leg and the client auto-answers it. Because both legs are inbound calls on the same single registration, this depends on the SDK allowing a secondanswer() for a distinct call ID.
In v2.27.0–v2.27.3 this second answer() was silently ignored: the
duplicate-answer guard keyed on any other active inbound call, so the second
leg stayed ringing with only a DUPLICATE_INBOUND_ANSWER (33007) warning
and no error or state change (webrtc#726).
v2.27.4 fixes this — the guard is scoped per call ID, so answering a
genuinely distinct second inbound call proceeds normally. The previous
call.options.attach = true workaround is no longer needed.
Auto-answer the server-dialed leg when it rings (identify it however your
backend marks it — e.g. a custom SIP header):
DUPLICATE_INBOUND_ANSWER (33007) warning now fires only when the same
call ID is answered twice (for example a duplicate WebSocket registration of the
same leg); it is warning-only and never tears down established media.
Best practices for concurrent calls
- One active call at a time — the SDK does not recommend having two fully active calls simultaneously. Use hold to manage the active call and accept/hold an inbound call while finishing the active one.
-
Assign distinct
remoteElementper call — use separateorelements for each call to avoidSHARED_REMOTE_ELEMENT_OVERWRITEwarnings and ensure independent playout lifecycles. -
Track calls by ID — use
call.idas the key in your application state. The call ID may change after reconnection (see recoveredCallId). -
Clean up on
destroyed— remove call references from your state whencall.state === 'destroyed'to prevent memory leaks. -
Use
hold()before answering — when accepting a second call, hold the first call first to avoid overlapping audio. -
One
TelnyxRTCinstance — keep a single client instance per tab/session. Multiple instances with the same credential causeDUPLICATE_INBOUND_ANSWERwarnings.
See Also
- Framework Integration — Per-call
remoteElementin React, Vue, Angular - Error Handling — Warning codes for multi-call scenarios
- Handle Reconnection — How calls survive reconnection
- IClientOptions — Client configuration
- ICallOptions — Call options including
remoteElement
Call Report Stats
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/monitor-call-quality.md
Call Report Stats
The Telnyx WebRTC JS SDK can automatically collect WebRTC statistics during and after calls. Use call reports to monitor quality, diagnose issues, and build real-time quality indicators.Enabling Call Reports
Real-Time Stats (telnyx.stats.frame)
Fires periodically during an active call (every callReportInterval ms):
StatsFrame Properties
Quality Thresholds
Building a quality indicator
Quality warning events
The SDK also emits structuredtelnyx.warning events when quality or connectivity thresholds are crossed. Use these warnings to drive user-facing indicators and collect diagnostics without parsing raw stats yourself:
LOW_LOCAL_AUDIO means RTP may still be flowing, but local microphone level is too low or silent. Ask the user to check microphone selection, mute state, and operating system input gain.
ICE_CANDIDATE_PAIR_CHANGED means the selected ICE path changed mid-call. The call may continue normally, but frequent changes are useful diagnostics for VPN changes, Wi-Fi handoffs, NAT rebinding, or relay fallback.
End-of-Call Report (telnyx.stats.report)
Fires when a call ends with a summary of the entire call:
Call Report Stats API
For SDK 2.25.20+, call reports are also available via HTTP API:API Response Structure
Key Fields for Diagnostics
Diagnosing Issues from Call Reports
DTLS stuck (“connecting”)
All relay candidates
forceRelayCandidate: true.
No candidates at all
stun.telnyx.com and turn.telnyx.com. See Network Requirements.
See Also
- IClientOptions —
enableCallReports,callReportInterval - Best Practices — Quality monitoring guidance
- Network Requirements — ICE/STUN/TURN configuration
- Debug Data & Call Quality Analysis — Interpreting debug output
Reconnection & Call Recovery
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/handle-reconnection.md
Reconnection & Call Recovery
Network interruptions happen — Wi-Fi drops, VPNs reconnect, laptops sleep. The Telnyx WebRTC JS SDK automatically handles reconnection so your users experience minimal disruption.How Reconnection Works
When the WebSocket connection tortc.telnyx.com drops:
- SDK detects the disconnect via WebSocket
closeorerrorevent, or via active-call signaling health checks when the socket is half-dead - SDK attempts reconnection after a randomized 2-6 second delay
- On successful reconnect, the SDK re-authenticates and re-attaches to existing calls
- If reconnection fails after
maxReconnectAttemptsattempts (default: 10), theRECONNECTION_EXHAUSTEDerror is emitted
When Calls Survive Reconnection
Calls can survive a brief WebSocket disconnect if:
Configuration:
keepConnectionAliveOnSocketClose is enabled:
- The PeerConnection (WebRTC media) stays alive even when the WebSocket (signaling) drops
- Audio continues flowing during the reconnection attempt
- On reconnect, the SDK re-attaches the existing call to the new WebSocket
- The call ID may change — use
recoveredCallIdto correlate
recoveredCallId
After a successful reconnection, the call may have a new ID. The previous ID is available as recoveredCallId:
When Calls Don’t Survive
When a call doesn’t survive reconnection, the SDK emits a
hangup state for that call.
Handling Reconnection in Your UI
Show reconnection status
Handle recovered calls
Handle signaling and media recovery warnings
During an active call, the SDK monitors WebSocket signaling liveness and media flow. If the browser reports the WebSocket as open but signaling stops flowing, the SDK emitstelnyx.warning and force-closes the socket to trigger reconnect + call reattach. If signaling is healthy but media is unhealthy, the SDK emits a media recovery warning and attempts ICE restart instead.
telnyx.ready, a recovered callUpdate, or a final hangup before cleaning up the call.
Inbound Calls After Reconnection
After a WebSocket reconnect, the browser may need to re-acquire microphone permissions to receive inbound calls. This is a browser security requirement, not an SDK limitation.mediaPermissionsRecovery
Handle microphone permission failures for inbound calls with a recoverable error pattern. When enabled and getUserMedia fails while answering, the SDK emits a recoverable telnyx.error event with resume() and reject() callbacks so your app can prompt the user to fix permissions before the call fails:
- An inbound call arrives and the user tries to answer
getUserMedia()fails (permission denied, device busy, etc.)- Instead of immediately failing the call, SDK emits a recoverable error with
resume()andreject()callbacks - Your app shows a UI prompting the user to grant permissions
- If the user fixes permissions and you call
resume(), the SDK retriesgetUserMedia() - If the user declines or
timeoutexpires, the call is terminated
mediaPermissionsRecovery only works for inbound calls. Recovery is attempted only when the initial getUserMedia call fails while answering.
Page Lifecycle and Call Report Flush
When the browser page is unloaded (close, reload, navigation), the SDK’s behavior depends on thehangupOnBeforeUnload option:
When
hangupOnBeforeUnload: false, active calls never hang up on unload, so a normal telnyx.stats.report (end-of-call report) would never fire for a call the user reloads or closes on. To prevent data loss, the SDK flushes an intermediate call report using navigator.sendBeacon / keepalive on visibilitychange → hidden — the last event reliably observable on both desktop and mobile before the page tears down.
visibilitychange → hidden flush is available since SDK v2.27.4. It mirrors the call report collector’s POST/retry/keepalive shape, ensuring the report reaches the stats endpoint even during page teardown.
Explicit Disconnect
When a user intentionally disconnects (e.g., signs out), you want to prevent automatic reconnection:clearReconnectToken() removes the session token that the SDK uses for automatic reconnection. After calling it, the SDK will not attempt to reconnect.
Common Issues
Rapid reconnection loops
Symptom: WebSocket connects and immediately disconnects, repeating rapidly. Cause: Usually an authentication issue — the JWT has expired or the credential has been revoked. Fix:- Check that the JWT is still valid
- Verify the credential still exists in the Telnyx Portal
- Check for
telnyx.errorevents withAUTH_FAILEDcode
RECONNECTION_EXHAUSTED
Symptom: SDK stops trying to reconnect after multiple failures.
Cause: Automatic reconnect reached maxReconnectAttempts (default: 10). The SDK uses a randomized 2-6 second delay between attempts; set maxReconnectAttempts: 0 only if your app should retry indefinitely.
Fix:
- Check network connectivity
- Verify
rtc.telnyx.comis reachable - Offer a manual “Reconnect” button in the UI:
Calls die after network change (Wi-Fi → Cellular)
Symptom: Call drops when switching networks, even withkeepConnectionAliveOnSocketClose.
Cause: The PeerConnection’s ICE candidates are tied to the old network. The new network has different candidates that weren’t part of the original negotiation.
Fix: This is a WebRTC limitation. The SDK attempts ICE restart, but it may not always succeed. The user will need to place a new call.
Configuration Summary
See Also
- TelnyxRTC Class — Client configuration and methods
- IClientOptions — Full configuration reference
- Error Handling — Error codes including reconnection errors
- Best Practices — Production reconnection guidance
Framework Integration
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/integrate-with-frameworks.md
Framework Integration
The Telnyx WebRTC JS SDK works with any JavaScript framework. This guide covers integration patterns for popular frameworks.React
Install
Using the React wrapper
The@telnyx/react-client package provides hooks and context providers:
Using the SDK directly
If you prefer to use the SDK without the React wrapper:Next.js
Next.js requires special handling because the SDK uses browser APIs (WebSocket, RTCPeerConnection) that don’t exist on the server.
Dynamic import
Client component (App Router)
Vue
Composable
Component
Angular
Service
General Patterns
Token fetching
All frameworks should fetch JWT tokens from a backend endpoint:Audio element management
The SDK auto-creates audio elements, but in some frameworks you may want to manage them yourself:Per-call media elements (concurrent calls)
Starting with SDK v2.27.4, you can assign a distinctremoteElement (and localElement) per call so concurrent calls in a single client session attach to independent / elements with independent playout lifecycles. Hanging up one call never tears down another call’s element.
Outbound calls — pass remoteElement at call creation:
remoteElement when answering:
client.remoteElement as the fallback default — backward compatible with existing single-call integrations.
If two calls share the same remoteElement, the SDK emits a SHARED_REMOTE_ELEMENT_OVERWRITE warning (33011) when the second call overwrites the first call’s MediaStream. Assign distinct elements to avoid this.
See Manage Multiple Calls for the full concurrent-call guide.
Cleanup
Always clean up on unmount/unload:See Also
- Quickstart — Get started in 5 minutes
- Authentication — JWT setup for production
- IClientOptions — Client configuration
- Best Practices — Production deployment guide
- Demo App — Full React reference application
Debug Data & Call Quality Analysis
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/debug-call-issues.md
Debug Data & Call Quality Analysis
When calls have quality issues, the Telnyx WebRTC JS SDK provides multiple tools to diagnose the problem. This guide covers collecting debug data, interpreting results, and common troubleshooting patterns.Data Collection Methods
Method 1: Call Reports (Production)
Enable call reports for production quality monitoring:Method 2: Debug Reports (Deep Troubleshooting)
Enable debug output for detailed troubleshooting data. Usedebug: true with debugOutput to control where the data goes:
- Full ICE candidate list with timestamps
- DTLS handshake state
- SDP offer/answer with codec negotiation
- Packet-level stats (bytes, packets, loss per direction)
- Audio level measurements
Accessing debug data
Call report data is available via the Call Report Stats API after the call ends:Interpreting debug data
Key sections to check:Method 3: Console Debug (Development)
Enabledebug: true to get verbose SDK logging in the browser console:
debug: true enables console logging by default.
Method 4: Debug Visualizer
Send debug output to the Telnyx debug visualizer for graphical analysis:- Call timeline with state transitions
- ICE candidate gathering progress
- DTLS handshake status
- Audio quality graphs (RTT, jitter, packet loss)
- Media flow direction
Common Issues & Diagnosis
One-Way Audio
Check:- Is DTLS connected? →
ice_data.transport.dtls_state === "connected" - Is audio being sent? → Check
bytesSentin stats - Is audio being received? → Check
bytesReceivedin stats - Which candidate type? →
ice_data.selected_pairshows host/srflx/relay
- Asymmetric TURN relay (two nominated candidate pairs, one sending and one receiving)
- Firewall blocks media in one direction
- VPN interferes with ICE candidates
Call Doesn’t Connect
Check:- WebSocket state →
client.connection.connected - ICE state →
ice_data.transport.ice_state - STUN accessibility → Any
srflxcandidates?
- Firewall blocks
rtc.telnyx.com:443(signaling) - Firewall blocks
stun.telnyx.com:3478(STUN) - Firewall blocks
turn.telnyx.com:3478(TURN over UDP/TCP) - Firewall blocks
turn2.telnyx.com:443(TURNS — TURN over TLS, last-resort fallback) - No
relaycandidates and symmetric NAT
Choppy Audio
Check:- Jitter →
stats.jitter > 50msis poor - Packet loss →
stats.packetLoss > 3%is poor - RTT →
stats.rtt > 300msis poor
- WiFi congestion (high jitter)
- Network congestion (high packet loss)
- Long routing path (high RTT)
- VPN adding latency
Echo
Common causes:- Built-in speakers + mic without echo cancellation
- Two audio elements playing the same stream
- Headset echo cancellation not working
- Recommend headphones
- Ensure only one audio element is active per call
- Check browser echo cancellation settings
Quick Diagnostic Script
Run this in the browser console during a problematic call:See Also
- Call Report Stats — Full stats API reference
- Error Handling — Error and warning codes
- Network Requirements — Firewall and connectivity
- IClientOptions —
debug,debugOutput - Best Practices — Quality monitoring
WebRTC JS SDK error handling
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/error-handling.md
Error Handling
The SDK exposes error-related behavior through three main channels:
Use
telnyx.ready to know when the client is authenticated and the gateway is ready. Do not treat readiness as a notification case.
What your application should react to
For production integrations, handle these events explicitly:
Do not treat every warning as a failed call. Media/signaling recovery warnings are intentionally emitted before the SDK attempts recovery, so your application can show a short degraded/reconnecting state while the SDK handles the recovery path.
Version note: The structured error and warning system (TELNYX_ERROR_CODES,telnyx.warning,TelnyxError) was introduced after v2.25.25. Exponential-backoff reconnection and browseronline/offlinehints (see Reconnection Behavior) ship in the next release. If you are on v2.25.25, see Error handling in v2.25.25 below.
Structured Errors (telnyx.error)
telnyx.error is the primary error surface. Listen for it to handle authentication failures, media errors, and connection issues.
Imports
Error event payload structure
Everytelnyx.error event is one of two shapes. Always check isMediaRecoveryErrorEvent(event) first, because the media-recovery variant carries callable recovery helpers.
Standard error event (the common case):
mediaPermissionsRecovery.enabled is set and getUserMedia() fails while answering):
error object (TelnyxError / ITelnyxError) exposes:
fatalvsrecoverable— two distinct fields, two distinct purposes:Recommended listener order: (1) check
event.error.fatal(always present on every error): tells your app whether the SDK has a recovery path.true= the SDK will not recover — take action now.false= the SDK is handling it — wait or continue.event.recoverable(only on media-permission recovery events): signals the app can recover via theresume()/reject()helpers. Onlyevent.recoverable === trueis meaningful;recoverableis absent on standard errors — do not branch onevent.recoverable === false.isMediaRecoveryErrorEvent(event)first, (2) then checkevent.error.fatalto decide whether to take action or wait, (3) then branch onevent.error.codefor tailored UX.
Getting and filtering errors by code
Media permission recovery
WhenmediaPermissionsRecovery.enabled is configured and getUserMedia() fails while answering a call, the error event includes recoverable: true with resume() and reject() callbacks:
Fatal errors and recommended handling
Fatal errors are situations the SDK will not recover from. When a fatal error fires, the affected call or session is dead — the SDK will not retry, reconnect, or reattach on its own. Your application must take the action described below. Every error event includesevent.error.fatal — a boolean that tells your app whether the SDK has a recovery path. true means the situation is terminal and you must act; false means the SDK is handling it (wait or continue). The Fatal? column below mirrors this field.
Uncommon errors — when to investigate.Errors that are not fatal by default (the SDK handles or continues):SDP_CREATE_OFFER_FAILED(40001),SDP_CREATE_ANSWER_FAILED(40002),SDP_SET_LOCAL_DESCRIPTION_FAILED(40003),SDP_SET_REMOTE_DESCRIPTION_FAILED(40004),PEER_CLOSED_DURING_INIT(44005), andWEBSOCKET_CONNECTION_FAILED(45001) are not expected during normal operation. If any of these recurs a few times or more, share the call with Telnyx support for investigation — their occurrence is most likely not caused by user actions and may indicate a browser, network, or server-side issue.
HOLD_FAILED (44001), BYE_SEND_FAILED (44003), SUBSCRIBE_FAILED (44004), WEBSOCKET_ERROR (45002), GATEWAY_FAILED (45004), ICE_RESTART_FAILED (47001), NETWORK_OFFLINE (48001). Two exceptions to know:
AUTHENTICATION_REQUIRED(46003) is non-fatal by default but becomes fatal whenautoReconnect: false. Re-authenticate usingclient.login().- The three media errors (
42001–42003) become recoverable (non-fatal) whenmediaPermissionsRecovery.enabledis set.
Re-authenticate without recreating the instance. ForLOGIN_FAILED(46001),INVALID_CREDENTIALS(46002), andAUTHENTICATION_REQUIRED(46003), useclient.login()on the existing connection:
Errors and warnings you should handle explicitly
These are the high-impact errors and warnings we recommend handling explicitly in every production integration. They are also marked ⚠️ in the reference tables below. Important errors (handle ontelnyx.error):
Important warnings (handle on
telnyx.warning):
Error code reference
Each error below is classified as fatal or non-fatal and includes what the SDK does automatically versus what you should do.SDP errors
Media errors
Call-control errors
ICE restart errors
WebSocket and transport errors
autoReconnectis enabled by default. Unless you explicitly setautoReconnect: false, the SDK handles reconnection automatically forWEBSOCKET_ERROR,GATEWAY_FAILED, and signaling-health recovery. You only need to callclient.connect()manually if you disabledautoReconnector afterRECONNECTION_EXHAUSTED.
Authentication and session errors
Re-authenticate without recreating the instance. ForLOGIN_FAILED(46001),INVALID_CREDENTIALS(46002), andAUTHENTICATION_REQUIRED(46003), useclient.login()to re-authenticate on the existing connection:
Structured Warnings (telnyx.warning)
Warnings are never fatal. They describe degraded behavior, quality issues, or situations that may need user action before the session breaks. The SDK continues operating after emitting a warning.
Imports
Warning event payload structure
Every warning event includes a structuredwarning object and the SDK sessionId. When a warning is associated with a specific call, callId is included. Recovery-related warnings add reason (and source for signaling recovery) for diagnostics:
warning object (ITelnyxWarning) exposes:
Use
warning.code for application logic. Use warning.message, warning.causes, and warning.solutions for support tooling or user-facing troubleshooting copy.
Getting and filtering warnings by code
Warning code reference
Network quality warnings
Data-flow warnings
Call connection warnings
Authentication and session warnings
Signaling health and recovery warnings
Signaling health warnings are emitted when the SDK detects a half-dead WebSocket during an active call — the browser still reports the socket as
OPEN, but no signaling bytes are flowing after a network interface change, VPN change, NAT timeout, or proxy/load-balancer drop. The SDK decides one recovery path:
- If signaling is unhealthy, it reconnects the WebSocket and reattaches active calls (
SIGNALING_RECOVERY_REQUIRED). - If signaling is healthy but media is unhealthy, it attempts ICE restart (
MEDIA_RECOVERY_REQUIRED). - It does not run both recovery paths at the same time.
online/offline events are treated as low-confidence hints and may accelerate a signaling health probe, but they do not directly trigger recovery.
Your application should keep the current call visible, show a reconnecting/degraded state, and wait for the next callUpdate, telnyx.ready, warning, or final hangup before cleaning up the UI.
Call Termination Data
When a call reacheshangup, inspect these fields on the Call object:
Common causes:
Socket Events
telnyx.socket.close
Delivers the browser CloseEvent. During a forced safety cleanup, the SDK emits a synthetic abnormal close with code: 1006 and wasClean: false.
Useful close codes:
telnyx.socket.error
Delivers { error: ErrorEvent, sessionId: string }. Browsers expose very little information for WebSocket errors. The SDK also emits telnyx.error with code 45002 (WEBSOCKET_ERROR) when ws.onerror fires.
Connection State Helpers
The browser session exposes WebSocket state helpers onclient.connection:
Example:
Reconnection Behavior
Ontelnyx.socket.close or telnyx.socket.error, the SDK clears subscriptions and resets gateway readiness state. autoReconnect is enabled by default; unless you set autoReconnect: false, the SDK automatically schedules connect(). Automatic reconnect stops after maxReconnectAttempts attempts (default: 10), or runs indefinitely when maxReconnectAttempts: 0.
Reconnect backoff
Reconnect attempts use exponential backoff with jitter (not a fixed/random delay):- Base delay starts at ~1s and doubles per attempt (~1s → ~2s → ~4s → ~8s → ~16s), capped at 30s.
- ±25% jitter is applied to avoid thundering-herd reconnects.
- The backoff counter resets only on a confirmed healthy registration (
REGED), not merely on socket open.
Browser online/offline handling
Browseronline/offline events are treated as low-confidence hints, not direct recovery triggers:
offlineemits theNETWORK_OFFLINE(48001) error for backward compatibility/telemetry and may accelerate a signaling health probe. It does not force a reconnect.onlineclears the browser-reported offline state for diagnostics but does not trigger recovery.- Recovery starts only from SDK-owned health evidence: liveness probe timeout, critical request timeout, peer failure, or no-RTP.
Socket close/error dedupe
When a socket fails, browsers commonly emit bothSocketError and SocketClose for the same disconnect. The SDK dedupes these by socket generation so a duplicate event cannot clear an already-scheduled reconnect timer or schedule a redundant reconnect. Stale events from an older, already-replaced socket are ignored.
Gateway retry behavior
- UNREGED / NOREG: Up to 5 registration retries with exponential backoff. After that,
LOGIN_FAILED(46001). - FAILED / FAIL_WAIT / TIMEOUT:
GATEWAY_FAILED(45004) emitted on first detection. The SDK retries with exponential backoff untilRECONNECTION_EXHAUSTED(45003).
Keeping media alive
IfkeepConnectionAliveOnSocketClose is true, the SDK preserves active peer connections while signaling reconnects. Recovery can create a new Call object with recoveredCallId.
Clearing reconnect stickiness
By default, the SDK reconnects to the sameb2bua-rtc instance. To break this stickiness and route to a different instance:
Note:clearReconnectToken()andskipLastVoiceSdkIdare available in@telnyx/webrtc@2.26.4.
Error Handling in v2.25.25
Important: If you are using SDK version 2.25.25, the error handling architecture is fundamentally different from the current version. This section documents the v2.25.25 error surface.
What is different in v2.25.25
Error events in v2.25.25
In v2.25.25, errors are emitted throughtelnyx.error and telnyx.notification:
telnyx.error — Session-level errors with raw Error objects (no .code property):
telnyx.notification — Carries both call lifecycle updates and error information. This is the only recommended way to handle media, peer connection, and signaling errors in v2.25.25. Do not listen for telnyx.rtc.mediaError, telnyx.rtc.peerConnectionFailureError, or telnyx.rtc.peerConnectionSignalingStateClosed directly — those are internal events. Use telnyx.notification instead:
Authentication errors in v2.25.25
Login errors are emitted ontelnyx.error with a type field for invalid credentials. You can re-authenticate using client.login() without recreating the TelnyxRTC instance:
Reconnection in v2.25.25
Reconnection behavior differs from the current version:autoReconnectis enabled by default; the SDK automatically reconnects unless you setautoReconnect: false- Reconnect uses a fixed/random 2-6 second delay (current SDK uses exponential backoff with jitter, capped at 30s)
- Browser
online/offlineevents directly drive reconnect (current SDK treats them as low-confidence hints) - No
maxReconnectAttemptsoption (current SDK defaults to 10 attempts and supportsmaxReconnectAttempts: 0for unlimited attempts) - No
clearReconnectToken()method - No
skipLastVoiceSdkIdoption keepConnectionAliveOnSocketCloseis available
Migrating from v2.25.25 to the latest
If you are upgrading from v2.25.25 to the latest version:- Replace
telnyx.notificationerror handling — usetelnyx.errorfor fatal errors andtelnyx.warningfor non-fatal conditions. Keeptelnyx.notificationfor call lifecycle only. - Replace
notification.type === 'userMediaError'handling withtelnyx.errorlistener switching onevent.error.code(42001,42002,42003). - Replace
notification.type === 'peerConnectionFailureError'handling withtelnyx.warninglistener forPEER_CONNECTION_FAILED(33004). - Replace
notification.type === 'signalingStateClosed'handling withtelnyx.warninglistener for the appropriate warning code. - Replace
ERROR_TYPE.invalidCredentialsOptionschecks withevent.error.code === TELNYX_ERROR_CODES.INVALID_CREDENTIALS(46002). Useclient.login()to re-authenticate without recreating theTelnyxRTCinstance. - Import new symbols:
TelnyxError,TELNYX_ERROR_CODES,TELNYX_WARNING_CODES,isMediaRecoveryErrorEvent. - Note
SESSION_NOT_REATTACHEDis an error, not a warning: in v2.26.0+ it isTELNYX_ERROR_CODES.SESSION_NOT_REATTACHED(48501) ontelnyx.error(fatal), not a warning.UNKNOWN_REATTACHED_SESSION(35002) is the separate warning.
Production Best Practices
Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/production-best-practices.md
Production Best Practices
Going from “it works on my machine” to “it works for all users, reliably” requires addressing security, reliability, performance, and monitoring. This guide covers the key areas.Authentication
Use JWT in production
Generate JWTs on your backend
Handle token refresh
One credential per user
Never share a Telephony Credential across multiple users. Each user must have their own JWT to ensure they receive their own incoming calls.Connection Management
One client instance per tab
Clean up on page unload
By default (hangupOnBeforeUnload: true), the SDK hangs up active calls and sends BYE on beforeunload:
hangupOnBeforeUnload: false to prevent the SDK from hanging up on unload. The SDK then flushes an intermediate call report on visibilitychange → hidden via keepalive so no call report data is lost:
hangupOnBeforeUnload: false, the SDK flushes a final call report on visibilitychange → hidden (the last reliably observable event on desktop and mobile) using keepalive so the report is not lost when the page tears down. Available since SDK v2.27.4.
Handle reconnection gracefully
Audio Quality
Request microphone with constraints
Monitor call quality
Enable call reports in production:Recommend headphones for agents
Built-in speakers + microphone create echo. For call center agents, recommend USB headsets or enforce echo cancellation.Network Configuration
Allowlist Telnyx domains
Ensure your firewall allows:Don’t force relay unless necessary
Error Handling
Always handle errors
Handle connection failures
Don’t show raw errors to users
Memory Management
Clean up call references
Remove event listeners
Monitoring & Observability
Enable call reports
Track key metrics
Log quality issues server-side
Deployment Checklist
See Also
- Authenticating Your App
- Configure Network & Firewall
- Handle Reconnection
- Monitor Call Quality
- Debug Call Issues
- Error Handling
TelnyxRTC Class
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/telnyxrtc.md
TelnyxRTC
TheTelnyxRTC class is the main entry point for the Telnyx WebRTC JS SDK. It manages the WebSocket connection to Telnyx’s signaling server and provides methods to create calls, handle events, and control the client lifecycle.
Constructor
connect() to establish the WebSocket connection.
Parameters:
Example:
Methods
connect()
Opens a WebSocket connection to rtc.telnyx.com and authenticates using the configured credentials.
telnyx.ready on success or telnyx.error on failure.
disconnect()
Closes the WebSocket connection and cleans up all active calls.
disconnect() when the user leaves your app to avoid zombie WebSocket connections. See Best Practices → Connection Lifecycle.
newCall(options)
Creates and places a new outbound call.
Returns: Call
See ICallOptions for all available options including custom headers, ICE configuration, and media settings.
off(event, handler)
Removes an event listener.
removeAllListeners()
Removes all event listeners from the client.
Properties
connection
Provides helpers to check the current connection state.
calls
An array of all active Call objects.
Events
Register event listeners usingclient.on(eventName, handler):
Connection Events
Call Events
Stats Events
Typical Usage
Reconnection
The SDK automatically reconnects when the WebSocket drops. You don’t need to handle this manually in most cases. For advanced reconnection handling, see Reconnection & Recovery. Key configuration:See Also
- IClientOptions — Full configuration reference
- Call Class — Call control methods
- Error Handling — Error and warning codes
- Best Practices — Production deployment guide
- Authentication — JWT generation and token refresh
Call Class
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/call.md
Call Class
TheCall object represents a voice call. It’s created by client.newCall() (outbound) or received via telnyx.notification (inbound).
Getting a Call Object
Outbound call
Inbound call
Properties
Call States
Methods
answer()
Answer an incoming call.
answer() when the call state is ringing. Calling answer() on an already-active call creates a duplicate PeerConnection, which causes one-way audio issues.
hangup()
End the call.
muteAudio() / unmuteAudio()
Toggle the microphone.
hold() / unhold()
Put the call on hold or resume it.
dtmf(digit)
Send a DTMF tone (0-9, *, #).
sendDigits(digits)
Send a sequence of DTMF digits.
Events
Register event listeners usingcall.on(eventName, handler):
Call State Events
Advanced
Access the PeerConnection
For custom WebRTC monitoring or manipulation:close() or setRemoteDescription() directly may break the call.
Custom headers
Add SIP headers to the INVITE for server-side correlation:Common Patterns
Simple outbound call with state handling
Inbound call with accept/reject UI
Hold and resume
See Also
- ICallOptions — Call configuration options
- INotification — Notification types and payloads
- TelnyxRTC Class — Client methods and events
- SDK Commonalities — Call states across all SDK platforms
- Best Practices — Production call management guide
IClientOptions
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/iclientoptions.md
IClientOptions
Options passed to theTelnyxRTC constructor to configure the client.
Quick Reference
Authentication
Choose one authentication method. See Authentication for the full guide.
Use
login_token (JWT) for production applications. Credentials (login + password) are long-lived with no automatic rotation. JWTs expire after 24 hours and support refresh. See Authenticating Your App.
JWT (production):
Anonymous Login
Connect to an AI assistant without requiring a credential. Theanonymous_login option accepts an object with the target configuration:
Example — Continue a conversation:
Connection
Control WebSocket, reconnection, and region behavior.
The SDK automatically reconnects when the WebSocket drops. There is no
reconnect option — reconnection is always automatic.
Enable call recovery:
ICE & Network
Configure STUN/TURN and ICE behavior.
The SDK automatically provisions STUN/TURN servers. You don’t need to configure
iceServers in most cases. See Network Requirements.
Force TURN for privacy:
Audio
Custom ringtone and ringback:
Call Reports
Enable post-call quality monitoring and real-time stats.
Call reports are enabled by default. You can customize the interval:
Debugging
Configure debug output for troubleshooting.
Enable console debug logging:
Media Permissions Recovery
Handle microphone permission failures for inbound calls with a recoverable error pattern.
When enabled and
getUserMedia fails while answering an inbound call, the SDK emits a recoverable telnyx.error event with resume() and reject() callbacks. Your app can prompt the user to fix permissions before the call fails:
Full Example
See Also
- TelnyxRTC Class — Client methods and events
- Authenticating Your App — JWT, credentials, and token refresh
- ICallOptions — Per-call configuration
- Handle Reconnection — Connection recovery
- Network Requirements — STUN/TURN/firewall
- Production Best Practices — Production configuration guide
ICallOptions
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/icalloptions.md
ICallOptions
Options passed toclient.newCall(options) to configure call behavior.
Quick Reference
Required Properties
Call Identity
Customize how the call appears to the remote party.
Example — Custom caller ID:
ICE & Network
Control how the call establishes media connectivity.
Example — Force TURN for privacy:
iceServers if you have custom infrastructure. See Network Requirements.
Media Configuration
Control audio devices and streams.
Example — Custom audio elements:
Advanced
Common Patterns
Basic voice call
Call with SIP URI
Call with custom headers (for Call Control correlation)
Privacy-focused call (force TURN)
See Also
- Call Class — Call control methods (answer, hangup, mute, hold)
- IClientOptions — Client-level configuration
- Network Requirements — ICE/STUN/TURN configuration
- Best Practices — Call management best practices
INotification
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/inotification.md
INotification
TheINotification object is emitted via the telnyx.notification event. It contains information about call state changes, media events, and SDK notifications.
Properties
Notification Types
Type: callUpdate
The most common notification type. Fired whenever a call’s state changes.
Call State Diagram
Type: userMediaError
Fired when the browser denies or fails to access media devices (microphone/camera).
- User clicked “Block” on the permission prompt
- No microphone/camera detected
- Another application is using the device
- System-level permission denied (OS settings)
Type: peerConnectionFailedError
Fired when the WebRTC PeerConnection fails to establish media. This usually means ICE negotiation or DTLS handshake failed.
- Firewall blocks UDP to TURN servers
- Symmetric NAT prevents direct connectivity
- VPN interfering with ICE
- Docker/container network issues
Type: signalingStateClosed
Fired when the PeerConnection’s signaling state becomes closed, indicating the SIP signaling channel has terminated.
callUpdate with state hangup.
Type: vertoClientReady
Fired when the client has successfully connected and authenticated with the Telnyx signaling server. This is equivalent to the telnyx.ready event but delivered as a notification.
Listening to Notifications
On the Client
On a Call
You can also listen on individual call objects:See Also
- Call Class — Call state and control methods
- TelnyxRTC Class — Client-level events
- Error Handling — Error and warning codes
- SDK Commonalities — Call states across all SDK platforms
Switch/Server Events
Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/sw-events.md
Switch/Server Events
The Telnyx signaling server sends events over the WebSocket connection during the call lifecycle. These are the raw server-side events — most applications should use the higher-leveltelnyx.notification event instead. See INotification for the recommended approach.
Most developers don’t need to handle these events directly. The SDK translates them into INotification objects. Use telnyx.notification unless you need low-level signaling details.
Event Reference
Client Lifecycle
Call Lifecycle
Media
Call Control
Presence & Registration
Event Flow: Outbound Call
Event Flow: Inbound Call
Listening to Server Events
For advanced use cases, you can listen to raw server events by enabling debug mode and parsing the WebSocket messages:telnyx.notification for stable event handling.
Server Events vs INotification
Use
telnyx.notification (INotification) for application code:
Gateway State Events
Thetelnyx.gateway.state event indicates when the WebSocket connection to the gateway goes up or down:
- Network interruption
- Server-side maintenance
- Credential revoked
- WebSocket timeout
See Also
- INotification — High-level notification types (recommended)
- Call Class — Call state and control methods
- TelnyxRTC Class — Client events
- Error Handling — Error and warning codes
- Architecture — How signaling and media flows work
How WebRTC Signaling Works
Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/webrtc-signaling.md
How WebRTC Signaling Works
WebRTC itself has no signaling protocol — it only defines how to establish media. The signaling (how you say “call this number” or “I’m ringing”) is up to the application. Here’s how the Telnyx WebRTC SDK does it.The Signaling Path
Key components:
VSP handles signaling only. B2BUA-RTC handles media only. They are separate systems.
WebSocket Connection
The SDK opens a single persistent WebSocket tortc.telnyx.com:
What the DNS resolution does
rtc.telnyx.com resolves to the nearest VSP based on DNS-based geo-routing:
If the DNS routes to a suboptimal VSP (e.g., an Indian client hitting FR5 instead of CN1), call latency increases. See Configure Network & Firewall for troubleshooting.
Outbound Call Flow
When you callclient.newCall():
What the SDK does at each step:
newCall()— Creates a Call object, starts ICE gathering- SIP INVITE — SDK sends invite message over WebSocket, VSP translates to SIP
- SDP negotiation — Codec selection (OPUS, PCMU, PCMA), ICE candidates exchanged
- Ringing — Remote party’s phone is ringing.
call.state === 'ringing' - Answer (200 OK) — Remote party picked up.
call.state === 'active' - Media flows — Audio transmitted via WebRTC (separate from signaling)
Inbound Call Flow
When someone calls your WebRTC client: What the SDK does:- Incoming INVITE — VSP receives SIP INVITE, pushes to SDK over WebSocket
callUpdatenotification —notification.call.state === 'ringing'- Your app decides — Call
call.answer()orcall.hangup() - Answer — SDK sends 200 OK, establishes WebRTC media
- Media flows — Two-way audio established
Session Description Protocol (SDP)
During call setup, both sides exchange SDP (Session Description Protocol) to agree on:
The SDK handles SDP negotiation automatically. You don’t need to construct SDP manually.
Codec Priority
The SDK’s default codec priority:- OPUS — Best quality, handles packet loss well, variable bitrate
- PCMU — G.711μ-law, universal compatibility, 64kbps
- PCMA — G.711A-law, European PSTN standard, 64kbps
WebSocket Reconnection
If the WebSocket drops, the SDK automatically reconnects: See Handle Reconnection for the full reconnection behavior and how to handle it in your app.Custom Headers
You can pass custom SIP headers in both directions:Outbound (your app → carrier)
Inbound (carrier → your app)
Inbound custom headers are available in the notification:What Signals What
Mute is a local operation — it stops sending audio from your microphone but doesn’t send any SIP signal. The remote party doesn’t know you’re muted (unless you tell them via your app).
See Also
How ICE & TURN Work
Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/ice-and-turn.md
How ICE & TURN Work
If you’ve ever wondered why some calls sound great and others don’t, the answer is often in ICE — the protocol that finds the best path for media between two endpoints. Understanding ICE helps you diagnose one-way audio, connection failures, and latency issues.The Problem ICE Solves
Two devices want to send audio to each other. But between them:- NAT (Network Address Translation) — Private IPs (192.168.x.x) aren’t reachable from the internet
- Firewalls — Block incoming connections
- Symmetric NAT — Even STUN can’t discover the public mapping
The Three Candidate Types
ICE discovers three types of candidates, in order of preference:1. Host Candidates (Local)
Your device’s local network interfaces (e.g.,192.168.1.105 on WiFi).
- Works when: Both devices are on the same LAN (rare for WebRTC calls)
- Quality: Best — zero extra latency
- Reality: Almost never used for WebRTC calls — both parties are rarely on the same network
2. Server-Reflexive Candidates (srflx) — via STUN
Your public IP, discovered by asking a STUN server (e.g.,203.0.113.5).
How STUN works:
- SDK sends a request to
stun.telnyx.com:3478 - STUN server sees the source IP (your public IP)
- STUN server sends it back: “Your public IP is 203.0.113.5”
- SDK creates a srflx candidate with that IP
- Works when: Your NAT allows inbound traffic to the mapped port (most home/office routers)
- Quality: Good — direct path, minimal extra latency
- Blockers: Symmetric NAT, strict firewalls
3. Relay Candidates — via TURN
An IP address allocated on a TURN server that relays your media (e.g.,64.16.248.1).
How TURN works:
- SDK authenticates with
turn.telnyx.com:3478over UDP or TCP (TURN/TLS on 443 is not currently supported) - TURN server allocates a relay address (e.g.,
64.16.248.1:50000) - All media is sent TO the TURN server, which forwards it to the remote party
- Remote party also sends TO the TURN server, which forwards to you
- Works when: Always — TURN is the fallback that never fails
- Quality: Adds latency (each packet goes through the TURN server) but guarantees connectivity
- Required when: Symmetric NAT, strict corporate firewalls, mobile carriers that block P2P
ICE Candidate Priority
The SDK tries candidates in this priority order:
In practice, most WebRTC calls use srflx (direct) or relay (TURN). Host candidates rarely work because both parties are on different networks.
A common misconception: “If my call uses TURN relay, something is wrong.”
False. TURN relay is normal and expected in many network conditions — mobile networks, corporate networks, some ISPs. The question isn’t “is TURN being used?” but “is the TURN server close to me?”
ICE Gathering Process
When a call starts, the SDK gathers candidates in this sequence:Trickle ICE
By default, the SDK uses Trickle ICE — it sends candidates as they’re discovered rather than waiting for all of them:ICE Connectivity Checks
Once both sides have candidates, ICE performs connectivity checks in this order:
If the STUN check fails (e.g., firewall blocks it), ICE tries the next candidate pair until it finds one that works — falling back to TURN relay if necessary.
DTLS — Encrypting Media
After ICE finds a working path, DTLS (Datagram Transport Layer Security) encrypts the media:
DTLS states:
If DTLS is stuck at
connecting, media won’t flow even if ICE connected. This is the #1 cause of one-way audio.
TURN Server Selection
Telnyx operates TURN servers in multiple regions:
The SDK automatically selects the nearest TURN server. You can override:
UDP vs TCP TURN
The SDK tries UDP first, falls back to TCP automatically. TURN/TLS on port
443 is not currently supported.
Troubleshooting ICE Issues
STUN fails (error 701)
Cause: Firewall blocksstun.telnyx.com:3478 (UDP)
Result: No srflx candidates — must use relay
Fix: Open UDP 3478 to STUN servers, or accept TURN relay
All ICE fails
Cause: Both STUN and TURN are blocked Result: Call cannot connect — no media path exists Fix: Open access to TURN servers on port3478 (UDP preferred, TCP fallback). TURN/TLS on port 443 is not currently supported.
Relay when srflx should work
Cause: Symmetric NAT — NAT mapping changes per destination Result: STUN-discovered port doesn’t accept inbound from B2BUA-RTC Fix: This is normal; TURN relay is the correct solutionHigh latency on relay
Cause: TURN server is geographically distant Result: 100ms+ added round-trip Fix: ConfigureiceServers to use a closer TURN server
See Also
- Configure Network & Firewall — Firewall rules and IP allowlists
- Debug Call Issues — How to diagnose ICE/TURN problems
- Monitor Call Quality — Check ICE stats in production
- Call State Lifecycle
- How WebRTC Signaling Works
Authentication Architecture
Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/authentication-architecture.md
Authentication Architecture
Telnyx WebRTC has three authentication methods. They’re not interchangeable — they form a hierarchy, and using the wrong one is the most common cause of security issues and unexpected behavior.The Hierarchy
- One Credential Connection can have multiple Telephony Credentials
- Each Telephony Credential can generate multiple JWTs
The Three Methods
1. Credential Connection (login + password)
- Credentials are long-lived — they remain valid until manually deleted
- No per-user isolation — one credential = one SIP registration
- No automatic rotation or refresh
2. Telephony Credential (credential-based login)
3. JWT (login_token)
- Time-limited — tokens expire 24 hours after creation (or when the parent credential expires, whichever comes first)
- Per-device — each device should use its own credential → its own JWT, preventing registration conflicts
- Refresh-aware — the SDK emits a
TOKEN_EXPIRING_SOONwarning (code 34001) before expiry, so your app can request a fresh token from your backend - Multiple concurrent sessions — different users/devices can each have their own JWT without overwriting each other’s SIP registration
Comparison
The JWT Flow in Production
Initial connection
Token refresh
JWTs expire after 24 hours. The SDK warns you before expiry so you can refresh without disconnecting: Your backend must:- Have a Telnyx API key (
TELNYX_API_KEY) - Expose an endpoint that creates tokens for a given telephony credential
- Return the token to the browser
- Handle token refresh requests when
TOKEN_EXPIRING_SOON(34001) fires
Why “One Credential Per User” Matters
Wrong — shared credential
When two users share one credential, the second registration overwrites the first. User A never receives incoming calls.Correct — separate JWTs
With JWTs, each token maps to a unique session. Multiple users can register concurrently without conflicts.Common Mistakes
See Also
- Authenticating Your App — Full code examples for all three methods
- IClientOptions —
login_token,login,passwordfields
Call State Lifecycle
Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/call-state-lifecycle.md
Call State Lifecycle
A call is a state machine. Understanding every state and transition is essential for building a reliable UI and handling edge cases like reconnection, transfer, and one-way audio.State Diagram
All States
Outbound Call States (Detailed)
new → ringing
- SDK creates a PeerConnection
- ICE gathering starts (host → srflx → relay candidates)
- SDP offer created with codec preferences
- INVITE sent over WebSocket to VSP
- VSP translates to SIP INVITE → carrier
ringing
- Remote phone is ringing (SIP 180 Ringing)
- You may hear ringback tone (generated locally by the SDK or played from network)
ringing → active
- SIP 200 OK received from carrier
- SDP answer processed — codecs and ICE candidates agreed
- DTLS handshake completes — media is encrypted
- SRTP audio starts flowing in both directions
- Audio element auto-created and attached to DOM
Inbound Call States (Detailed)
ringing (incoming)
- VSP receives SIP INVITE from carrier
- VSP pushes invite message to SDK over WebSocket
- SDK creates a Call object with
state: 'ringing' telnyx.notificationfires withcallUpdate
ringing → active (answer)
- SDK sends 200 OK over WebSocket
- getUserMedia() — browser requests microphone permission
- ICE gathering starts
- SDP answer sent
- DTLS handshake
- Media flows
call.answer() triggers getUserMedia(). If the user hasn’t granted microphone permission, the browser will show a permission dialog. The call won’t be fully active until permission is granted.
ringing → destroyed (reject)
Active Call States
active → held
- SDK sends re-INVITE with
sendonlymedia direction - Remote party’s audio continues (they hear hold music if configured)
- Your audio stops sending (microphone muted at SIP level)
- Remote party receives a
callUpdatewith their call state changing
held → active
- SDK sends re-INVITE with
sendrecvmedia direction - Two-way audio resumes
Reconnecting State
- ICE connectivity checks fail (network change)
- DTLS session breaks
- WebSocket still connected but media path lost
- ICE restart — re-gathers candidates
- Attempts to re-establish DTLS
- If successful →
call.state → 'active'(call resumes) - If fails after timeout →
call.state → 'destroyed'(call drops)
Destroyed State
All calls end up here. It’s terminal — no further transitions.
Your app: Clean up UI. Upload call report. Show call summary if applicable.
State Transition Matrix
Common Pitfalls
Double answer
Not handling destroyed
Missing reconnecting
See Also
- Call Class — Methods for each state
- INotification — All notification types
- Handle Reconnection — Reconnection flow
- Handle Multiple Calls — Hold/resume patterns
- How WebRTC Signaling Works — SIP message flow
WebRTC JS ChangeLog
Source: https://developers.telnyx.com/development/webrtc/js-sdk/changelog.md
React quickstart
Source: https://developers.telnyx.com/development/webrtc/react-sdk.mdThe React SDK can be added to your application by installing the npm packages:
Client initialization
In theTelnyxRTCProvider component, you can pass credentials and options objects with custom ringtones:
Phone component
In thePhone component, you would subscribe to the notifications from the WebRTC client, specify callbacks for Telnyx client event handlers, and define an Audio element.
First import the React client:
Phone function component where you will manage event handlers using callbacks and control audio stream in the “ element:
Sample React app
Check out our sample React application for a full implementation of the Telnyx Voice SDK with React components.Voice native iOS Client SDK
Source: https://developers.telnyx.com/development/webrtc/ios-sdk.md
WebRTC iOS Client
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/txclient.md
WebRTC iOS Call
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/call.md
WebRTC iOS Call
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/call-extensions.md
WebRTC iOS Client
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/txclient-extensions.md
WebRTC iOS Call State
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/enums/call-state.md
WebRTC iOS TxClientDelegate
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/protocols/tx-client-delegate.md
WebRTC iOS Call Info
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-call-info.md
WebRTC iOS Client Configuration
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-config.md
WebRTC iOS Client Push Notifications Configuration
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-push-config.md
WebRTC iOS Client Push IP Notifications Configuration
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-push-ip-config.md
iOS Portal Setup
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/portal-setup.md
iOS Push Notification Setup
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/app-setup.md
Troubleshooting
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/troubleshooting.md
WebRTC iOS SDK AI Voice Assistant Introduction
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/introduction.md
WebRTC iOS SDK AI Voice Assistant Anonymous Login
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/anonymous-login.md
WebRTC iOS SDK AI Voice Assistant Starting Conversations
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/starting-conversations.md
WebRTC iOS SDK AI Voice Assistant Text Messaging
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/text-messaging.md
WebRTC iOS SDK AI Voice Assistant Transcript Updates
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/transcript-updates.md
WebRTC Stats
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/stats.md
WebRTC iOS SDK Error Handling
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/error-handling.md
WebRTC iOS ChangeLog
Source: https://developers.telnyx.com/development/webrtc/ios-sdk/changelog.md
WebRTC Android Quickstart
Source: https://developers.telnyx.com/development/webrtc/android-sdk/quickstart.md
Android Voice Client SDK
Source: https://developers.telnyx.com/development/webrtc/android-sdk.md
WebRTC Android Client
Source: https://developers.telnyx.com/development/webrtc/android-sdk/classes/txclient.md
WebRTC Android Call
Source: https://developers.telnyx.com/development/webrtc/android-sdk/classes/call.md
WebRTC Android Config
Source: https://developers.telnyx.com/development/webrtc/android-sdk/config/txconfig.md
WebRTC Android ReceivedMessageBody
Source: https://developers.telnyx.com/development/webrtc/android-sdk/socket/receivedmessagebody.md
WebRTC Android SocketResponse
Source: https://developers.telnyx.com/development/webrtc/android-sdk/socket/socketresponse.md
Android Portal Setup
Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/portal-setup.md
Notification Quickstart for Android
Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/quickstart.md
Android Push Notification Setup
Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/app-setup.md
Android Push Troubleshooting
Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/troubleshooting.md
WebRTC Android SDK AI Voice Assistant Introduction
Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/introduction.md
WebRTC Android SDK AI Voice Assistant Anonymous Login
Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/anonymous-login.md
WebRTC Android SDK AI Voice Assistant Starting Conversations
Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/starting-conversations.md
WebRTC Android SDK AI Voice Assistant Text Messaging
Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/text-messaging.md
WebRTC Android SDK AI Voice Assistant Transcript Updates
Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/transcript-updates.md
WebRTC Stats
Source: https://developers.telnyx.com/development/webrtc/android-sdk/stats.md
WebRTC Call Reports
Source: https://developers.telnyx.com/development/webrtc/android-sdk/call-reports.md
WebRTC Call Reports
The Telnyx Android SDK automatically collects detailed call statistics during WebRTC calls and sends them to Telnyx for troubleshooting and monitoring purposes. This feature helps diagnose call quality issues, connection problems, and provides insights into call performance.Overview
When enabled, the SDK collects:- Call summary: Call identifiers, timestamps, duration, and device information
- Connection metrics: ICE states, DTLS states, signaling transitions
- Media statistics: Packet loss, jitter, round-trip time, audio levels
- Network information: Selected ICE candidates, transport details
Enabling Call Reports
Call reports are automatically enabled when you connect to the Telnyx WebRTC service. The SDK handles data collection and upload transparently. Call reports are sent automatically when a call ends. No additional configuration is required.Accessing Local Call Reports
For debugging purposes, you can access the call report JSON file that is saved locally after each call:/call_stats/call_stats_.json
Call Report JSON Structure
The call report JSON contains the following sections:Top-Level Identifiers
Summary Section
Contains high-level call information:Stats Array
Contains interval-based statistics captured during the call. Each interval (typically 5 seconds) includes:Android Extra Section
Contains Android-specific debugging information:Metrics Reference
Audio Inbound Metrics
Audio Outbound Metrics
Connection Metrics
Troubleshooting with Call Reports
Call reports can help diagnose common issues:High Packet Loss
Look atpacketsLost in the audio inbound stats. Values above 1-2% may indicate network issues.
Audio Quality Issues
CheckjitterAvg and concealmentEvents. High jitter (>30ms) or frequent concealment events indicate audio quality degradation.
Connection Failures
Review theconnectionTimeline in android_extra. Look for:
ICE_FAILED- Network connectivity issuesDTLS_FAILED- TLS/security handshake failures- Long gaps between
ICE_CONNECTEDandDTLS_CONNECTED(>5 seconds)
One-Way Audio
Check if:packetsReceivedis 0 (not receiving audio)audioLevelAvgis 0 (microphone not capturing)- Review microphone permissions in
deviceInfo.permissions
Privacy & Data Handling
Call reports are sent securely to Telnyx and are used solely for:- Troubleshooting call quality issues
- Monitoring service health
- Improving SDK performance
See Also
- WebRTC Stats - Real-time call quality metrics
- Error Handling - SDK error codes and handling
- Troubleshooting Guide - Common issues and solutions
WebRTC Android SDK Error Handling
Source: https://developers.telnyx.com/development/webrtc/android-sdk/error-handling.md
WebRTC Android ChangeLog
Source: https://developers.telnyx.com/development/webrtc/android-sdk/changelog.md
React Native SDK
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk.md
React Native SDK Quickstart
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/quickstart.md
Call
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/classes/call.md
TelnyxVoipClient
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/classes/telnyxvoipclient.md
CredentialConfig
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/credentialconfig.md
TokenConfig
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/tokenconfig.md
TelnyxVoipClientOptions
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/telnyxvoipclientoptions.md
TelnyxVoiceAppOptions
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/telnyxvoiceappoptions.md
Portal Setup
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/portal-setup.md
App Setup
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/app-setup.md
Error Handling
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/error-handling.md
Changelog
Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/changelog.md
Flutter Voice Client SDK
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk.md
WebRTC Flutter Client
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/txclient.md
WebRTC Flutter Call
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/call.md
Flutter WebRTC SDK Message
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/messages/telnyx-message.md
Flutter WebRTC SDK Socket Error Message
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/messages/telnyx-socket-error.md
WebRTC Flutter Call State
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/enums/call-state.md
Flutter WebRTC SDK Socket Message Handler
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/event-handlers/on-socket-message-received.md
Flutter WebRTC SDK Socket Error Handler
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/event-handlers/on-socket-error-received.md
WebRTC Flutter Client Configuration
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/config.md
WebRTC Flutter Incoming Invite Object
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/incoming-invite-params.md
WebRTC Flutter Client Push Notifications Configuration
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/push-metadata.md
Flutter Push Notification Portal Setup
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/portal-setup.md
Flutter Push Notification App Setup
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/app-setup.md
Flutter Push Troubleshooting
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/troubleshooting.md
WebRTC Flutter SDK AI Voice Assistant Introduction
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/introduction.md
WebRTC Flutter SDK AI Voice Assistant Anonymous Login
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/anonymous-login.md
WebRTC Flutter SDK AI Voice Assistant Starting Conversations
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/starting-conversations.md
WebRTC Flutter SDK AI Voice Assistant Text Messaging
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/text-messaging.md
WebRTC Flutter SDK AI Voice Assistant Transcript Updates
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/transcript-updates.md
WebRTC Stats
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/stats.md
WebRTC Flutter SDK Error Handling
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/error-handling.md
WebRTC Flutter ChangeLog
Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/changelog.md
Trusted Calling
Overview
Source: https://developers.telnyx.com/docs/branded-calling/overview.mdBranded Calling is currently in beta. We’re rolling it out gradually, so some features may not be fully available yet and behavior can change while we finalize the product. The exact information displayed on the recipient’s phone depends on many factors (carrier network, device manufacturer, device type, OS version, etc.). If something doesn’t work exactly as documented, it’s most likely still being enabled, and we appreciate your patience as we get everything ready. For the latest on availability and how branded calls are delivered, see Making calls with Branded Calling. This feature is currently supported in the US only.
Overview
Branded Calling displays your verified business identity on the recipient’s phone screen before they answer. Instead of seeing a bare phone number, or worse, “Spam Likely”, recipients see your business name, logo, and the reason for your call. The screenshots below show Branded Calling in action.How it works
- You register your business as an Enterprise and create a display identity (Display Identity Record) with your name, logo, and call reason.
- Telnyx vets the DIR, verifying your business identity, IP ownership, and compliance.
- You associate your Telnyx phone numbers with the verified DIR.
- When you place a call from those numbers, Telnyx automatically signs the call with a cryptographic token (SHAKEN PASSporT) containing your DIR’s rich call data.
- The terminating carrier verifies the signature and renders your DIR info on the recipient’s device.
Resource hierarchy
- An Enterprise can have multiple Display Identity Records (DIRs).
- Each Display Identity Record has its own display name, logo, call reasons, and phone numbers.
- A Phone Number belongs to exactly one Display Identity Record.
- Phone numbers are added in batches: each
POSTcreates one batch, and the batch is the unit that goes through carrier-network vetting. - Call reasons are set at the Display Identity Record level.
Key concepts
Ecosystem
Branded Calling is built on an industry-wide registry, managed by CTIA. The registry ensures trust among all participants through common technical and governance frameworks. Telnyx handles all ecosystem interactions on your behalf, you interact only with the Telnyx API.Next steps
- Quickstart guide, get your first branded call working
- Pricing, Branded Calling pricing details
- Display Identity Records, create and manage display identities
- Phone Numbers, associate numbers with DIRs
- Call Reasons, configure what recipients see
- Infringement Claims, what to do if a claim is filed against your DIR
Quickstart
Source: https://developers.telnyx.com/docs/branded-calling/quickstart.mdBranded Calling is in beta. Learn more in Making calls with Branded Calling. This walk-through takes you from a fresh account to a verified Display Identity Record (DIR) with phone numbers attached. You’ll need a verified or enterprise-level Telnyx account and an API key.
Before you begin
You’ll need:- A Telnyx account with verified or enterprise access and an API key.
- One or more US Telnyx phone numbers in your inventory. (Branded Calling is currently US-to-US; non-US numbers won’t produce a branded result yet.)
- Your business legal details (legal name, EIN, jurisdiction of incorporation, addresses, contacts).
- A logo image, 256×256 BMP only, ≤1 MB, hosted at a publicly-reachable HTTPS URL (optional, you can submit without one). Most design tools export PNG by default; convert to BMP with any standard image editor (Preview, Photoshop, ImageMagick, GIMP) before hosting.
- Supporting documents (e.g. business registration, letter of authorization). Upload each one through the Telnyx Documents API first; the API gives you back a
document_idthat you reference here.
Step 1: Accept the Branded Calling Terms of Service
Read the full terms at telnyx.com/terms/branded-calling.Step 2: Create an Enterprise
id from the response, you’ll need it for the activation step.
For the full field reference (every required field, enum values, contact + address shape), see Enterprises.
Step 3: Activate Branded Calling on the enterprise
Branded Calling is a paid product that must be explicitly activated per enterprise. Without this step, DIR creation in Step 5 returns400 with code=10015 and a detail pointing back to this endpoint.
400 with detail: "Branded calling registration has not completed" for roughly 10 seconds. Wait and retry, or poll the enterprise until activation settles. Both endpoints are idempotent.
A 403 here means the Branded Calling Terms of Service hasn’t been accepted yet (back to Step 1).
Activating Branded Calling on an enterprise is billable. See Branded Calling pricing.
Step 4: (Optional) Validate your call reasons up front
When a DIR’s call reasons are all pre-approved, the call-reason vetting check passes automatically, which can speed up review (the DIR is still vetted and is not auto-approved). Run them through the validator before creating the DIR, both reasons below are on the pre-approved catalogue, so this example returnsall_pre_approved: true:
The body is a bare JSON array of strings: do not wrap it in { "call_reasons": [...] }.
If you instead send a mix that includes any custom string (for example "Patient Follow-up", which is not on the pre-approved list), the response is requires_manual_vetting: true with the offending entries in non_approved_reasons. Custom reasons are still allowed; the call-reason check is then reviewed manually, which can take longer.
Pull the live pre-approved catalogue with GET /v2/call_reasons (see the Call Reasons guide) and copy the reason strings verbatim into your DIR to help speed up the call-reason check.
Step 5: Create a DIR
A Display Identity Record (DIR) defines what recipients see on their phone: display name, logo, and call reason.400 (with an error code such as 10015, 10025, or 10026 and a source.pointer to the offending field):
The DIR is created in
draft status. Save the id, this is your dir_id.
Step 6: Submit for vetting
submitted, then in_review. Telnyx then reviews and approves the DIR out-of-band (this is not instantaneous; pre-approved call reasons can shorten it - see Step 4). Wait for the DIR to reach verified before attaching phone numbers in Step 7. Outcomes:
verified, approved. Phone numbers can now be attached.rejected, fixable. Readrejection_reasonson the DIR and thevetting_comment/rejection_reasonentries onGET /v2/dir/{dir_id}/commentsfor context,PATCHthe offending fields, thenPOST /submitagain.unsuccessful, system error. Same handling as rejected.permanently_rejected, terminal. The only exit isDELETE /v2/dir/{dir_id}(remove any attached phone numbers first, or the delete returns400).
verified.
Once a DIR is verified, a non-trivial PATCH that actually changes a field moves it back to draft and tears down the live registration. You must POST /submit and be re-approved before it serves traffic again. Avoid editing a verified DIR unless you intend to re-vet it.
While waiting, poll GET /v2/dir/{dir_id} for the current status. Use a sensible cadence (e.g. once every 30-60 seconds); don’t poll in a tight loop.
If /submit fails with a 400 and the DIR has an open infringement claim, resolve the claim first, see Infringement Claims.
Step 7: Attach phone numbers
Once the DIR isverified, you can attach phone numbers. A signed Letter of Authorization (LOA) is required on every add request.
First upload your signed LOA to the Telnyx Documents API and capture the returned id:
id as document_id:
- A
documentsarray with at least oneletter_of_authorizationentry is required (1-20 documents). The request is rejected with400if it’s missing or has no LOA entry. - Up to 15 numbers per request.
- Atomic: if any number is invalid, already attached, or not in your inventory, the entire batch is rejected with
400and nothing is written. The error response identifies the offending number(s); remove them and re-submit the rest. - Numbers must be E.164 format and present in your Telnyx inventory.
- The DIR must be in
verifiedstatus. Adding numbers to a DIR in any other status returns400withdetail"...DIR must be verified".
POST creates one batch. Track batch progress through carrier-network vetting:
Step 8: Make branded calls
Once a phone number reachesverified status, it is eligible to display your branded identity on outbound calls.
The recipient’s experience depends on their carrier and device supporting branded calling. Coverage is strongest on major US carriers with compatible devices.
What’s next
- Display Identity Records (DIRs), full DIR lifecycle, statuses, editing, deletion.
- Phone Numbers, adding/removing numbers and inspecting batches.
- Call Reasons, the pre-approved list and the validator.
- Infringement Claims, what to do if a claim is filed against your DIR.
Pricing
Source: https://developers.telnyx.com/docs/branded-calling/pricing.md
Pricing
Branded Calling pricing has three components:
For the full pricing details, see the Branded Calling pricing page.
Overview
Source: https://developers.telnyx.com/docs/branded-calling/enterprises.md
Overview
An Enterprise represents your business entity on the Telnyx platform. It’s the top-level resource you must register before you can use Branded Calling to display your verified business identity (display name, logo, call reason) on outbound calls.What you need
To create an enterprise, you’ll need:Quick start
1. Accept the Branded Calling Terms of Service
You must agree to the Branded Calling ToS before activating the product.2. Create an enterprise
id, use this enterprise ID for all subsequent API calls.
3. Activate Branded Calling on the enterprise
Branded Calling is a paid product that must be explicitly activated per enterprise. Without this step, DIR creation returns400 with code=10015 and a detail pointing back to this endpoint.
400 right after activation, wait a moment and retry. Both endpoints are idempotent.
A 403 here means the Branded Calling Terms of Service hasn’t been accepted yet (back to step 1).
Activating Branded Calling is billable. See Branded Calling pricing.
4. Next steps
- Create your first Display Identity Record (DIR) and submit it for vetting.
Reusing the enterprise
Register the enterprise once and reuse it for all of your Branded Calling work. The API collects all required fields up front so you don’t need to update them later.Access requirements
All Branded Calling endpoints require a verified or enterprise-level Telnyx account. Trial and standard paid accounts cannot access these features. See Account Levels and Capabilities for details on upgrading.Overview
Source: https://developers.telnyx.com/docs/branded-calling/brands.md
Overview
A Display Identity Record (DIR) defines what recipients see on their phone screen when you call. Each DIR has a display name, an optional logo, and 1-10 call reasons. Display Identity Records must be vetted and approved by Telnyx before they become active. Once a DIR reachesverified status, calls placed from any phone number attached to it will display the branded identity on supported carriers and devices.
Prerequisites
Before creating a DIR:- The parent Enterprise must exist (
POST /v2/enterprises). - The Branded Calling Terms of Service must be accepted (
POST /v2/terms_of_service/branded_calling/agree). - Branded Calling must be activated on the enterprise (
POST /v2/enterprises/{enterprise_id}/branded_calling). Without this, DIR creation returns400withcode=10015. Activation completes asynchronously; if DIR creation returns400immediately after, retry - both endpoints are idempotent.
API endpoints
Required fields
These are the DIR-level required fields. Anything related to the legal entity (legal name, EIN, addresses, contacts, jurisdiction) lives on the parent Enterprise: not on the DIR.Optional fields
Logo requirements
The logo must be a BMP image, exactly 256×256 pixels, ≤1 MB, ≤32-bit color depth, hosted at a publicly-reachable HTTPS URL. PNG, JPEG, and other formats are rejected at create /PATCH time with a 400. Most design tools export PNG by default, convert to BMP with any standard image editor (Preview, Photoshop, ImageMagick, GIMP).
Document types
When you attachdocuments to a DIR, each entry’s document_type must be one of:
letter_of_authorization, business_registration, articles_of_incorporation, tax_document, ein_letter, trademark_registration, website_ownership, business_license, professional_license, government_id, utility_bill, bank_statement, other
The actual file is uploaded separately via the Telnyx Documents API; the document_id you receive from that upload is what you reference here.
Display Identity Record statuses
Updating a DIR
PATCH is allowed in draft, rejected, unsuccessful, suspended, and verified.
A few things to know:
- For
draft/rejected/unsuccessful,PATCHis a pure edit. The status doesn’t change. CallPOST /submitto re-vet when ready. suspendedmeans an infringement claim is attached.PATCHitself is allowed and leaves the status unchanged, butPOST /submitis blocked with a409while the claim is stillpendingorcontested(theno_active_claimsgate). To revise content and re-vet during an open claim, usePUT /v2/dir/{dir_id}/infringement_updateinstead - see Infringement Claims. The plainPATCH+POST /submitflow only works once the claim isresolved(e.g.resolution = modified, which leaves the DIRsuspendedwith the claim closed).- For
verified, aPATCHthat actually changes a field flips the DIR back todraftand tears down the live registration. The DIR stops serving its branded identity on calls until youPOST /submitand Telnyx re-approves it. Don’t edit a live verified DIR unless you intend to take it out of service and re-vet it. - If you provide
logo_url, it is re-downloaded and re-validated on everyPATCH. If validation fails the DIR isn’t updated. documentsare append-only, existing documents are never removed by aPATCH.
Resubmitting after rejection
When a DIR isrejected or unsuccessful, the headline reasons are in the rejection_reasons array on the DIR itself; the detailed reviewer notes appear on the comments thread. Read both. Fix the issues with PATCH, then submit again:
Deleting a DIR
draft, rejected, unsuccessful, verified, suspended, expired, infringement_claimed, and permanently_rejected. The mid-vetting statuses submitted and in_review return 400.
The DIR must have no phone numbers still attached. If any numbers are attached, the delete returns 400 (“DIR has N phone number(s) still attached. Delete every phone first, then delete the DIR.”). Remove them with DELETE /v2/dir/{dir_id}/phone_numbers first, then delete the DIR.
Returns 409 if the DIR has a pending or contested infringement claim. Customers can only contest the claim, Telnyx adjudicates resolution.
Overview
Source: https://developers.telnyx.com/docs/branded-calling/bc-phone-numbers.md
Overview
After your DIR reachesverified status, attach your Telnyx phone numbers to it. Outbound calls from those numbers automatically display the DIR’s name, logo, and call reason on supported carriers and devices.
Numbers are added in batches: each POST creates one batch, and the batch is the unit that goes through carrier-network vetting. A phone number can be attached to only one DIR at a time.
Pre-conditions
- The DIR must be in
verifiedstatus. Adding numbers to a DIR in any other status returns400(detail: ”…DIR must be verified”). - The phone numbers must already be in your Telnyx phone-number inventory.
- Numbers must be in strict E.164 format: a leading
+followed by 10-15 digits (no spaces, dashes, or parentheses). - A signed Letter of Authorization (LOA) must accompany every add request. Upload it to the Telnyx Documents API first and reference the returned
idas adocument_id.
API endpoints
Each path above also has an equivalent form that includes the enterprise:
/v2/enterprises/{enterprise_id}/dir/{dir_id}/phone_numbers (and the
phone_number_batches variants). Both forms share the same request and
response contract.
Render the Letter of Authorization (optional)
You can have Telnyx generate a pre-filled LOA PDF for the DIR instead of writing your own.POST /v2/dir/{dir_id}/loa returns an application/pdf. The enterprise identity and DIR display name are filled in server-side; you supply the phone numbers you intend to authorize (the same list you will add below), and optionally a third-party agent block and a drawn signature.
phone_numbers: 1-15 numbers in+E164format (the same numbers you authorize below).agent: optional. The third-party reseller/partner managing the numbers; omit when you work with Telnyx directly.signature: optional. When provided, the PDF embeds the signature image and printed name. When omitted, the PDF comes back unsigned so you can sign it externally.
document_id as a letter_of_authorization document when adding numbers (below).
Adding phone numbers (creating a batch)
Adocuments array containing at least one Letter of Authorization is required. First upload the signed LOA to the Telnyx Documents API:
document_id:
- A
documentsarray with at least oneletter_of_authorizationentry is required (1-20 documents). - The
phone_numbersarray must contain 1-15 numbers per request. - The batch is atomic: if any number fails validation (invalid format, duplicate within the request, not in your inventory, already attached to another DIR, or in a terminal
permanently_rejectedstate), the entire request is rejected with400and nothing is written. On success the response is201with{"data": [...]}. On failure the body is the standard Telnyx error envelope with oneerrors[]entry per failure category, identifying the offending numbers; remove them and re-submit the rest. - A
400is also returned if the DIR is in a status that cannot accept new numbers, including asuspendedDIR with an open infringement claim (thedetailthen includes the open claim IDs).
Phone number statuses
Inspecting batches
A batch is the unit of carrier-network vetting. Once a batch reachesverified (every number in it is verified), branded calling is active for the whole batch.
Listing numbers
page[number], page[size], max 250).
Removing numbers
data, and numbers that can’t (not associated, invalid, etc.) come back in a meta.errors array on the same response. If every number fails, the response is a 400 with the standard Telnyx error envelope.
Removing a number tears down its registration on the Branded Calling network and frees the number to be attached to a different DIR.
Overview
Source: https://developers.telnyx.com/docs/branded-calling/call-reasons.md
Overview
A call reason is a short string explaining why your business is calling, for example, “Appointment Reminder” or “Delivery Update”. Call reasons are set at the DIR level as a list of 1-10 strings (each up to 64 characters) at DIR-create time. Telnyx maintains a list of pre-approved call reasons. When a DIR’scall_reasons are all pre-approved, the call-reason vetting check passes automatically, which can help speed up review. If any reason is custom (not pre-approved), that check is reviewed by a human instead. Either way the DIR still goes through full vetting; pre-approved reasons are not auto-approved.
API endpoints
List pre-approved call reasons
Defaultpage[size] is 100 (max 250).
reason strings verbatim in your DIR’s call_reasons array to help speed up the call-reason check during vetting.
Validate a list of call reasons
Before creating a DIR, check whether the reasons you plan to use are pre-approved:
The body is a bare JSON array of strings: do not wrap it in { "call_reasons": [...] }. This is unusual for Telnyx APIs; copy the example verbatim.
The result is returned under a top-level data object with three fields:
all_pre_approved (true when every reason is pre-approved and enabled),
requires_manual_vetting (true when at least one reason is not pre-approved),
and non_approved_reasons (the list of reasons that are not pre-approved).
Constraints
Overview
Source: https://developers.telnyx.com/docs/branded-calling/terms-of-service.md
Overview
You must accept the Branded Calling Terms of Service before activating Branded Calling on any enterprise (POST /v2/enterprises/{enterprise_id}/branded_calling); without it, activation returns 403. Read the full terms at telnyx.com/terms/branded-calling.
Acceptance is a one-time, idempotent action per user. If Telnyx publishes a new ToS version, you may need to re-accept.
API endpoints
The generic
GET /v2/terms_of_service/status, GET /v2/terms_of_service/agreements,
and GET /v2/terms_of_service/info endpoints accept a product_type query
parameter that defaults to branded_calling.
Check your status
product_type=branded_calling. If omitted, it defaults to branded_calling.
Accept Branded Calling ToS
Overview
Source: https://developers.telnyx.com/docs/branded-calling/infringement-claims.md
Overview
If a third party believes your DIR’s display name, logo, or content infringes on a protected right (trademark, copyright, etc.), they can file an infringement claim through Telnyx. Claims are filed and adjudicated by Telnyx, you cannot create a claim through this API, but you can read and contest claims filed against your own DIRs. While a claim ispending or contested:
- The DIR is moved to
suspended. - Branded calling pauses for the affected DIR.
- You cannot add phone numbers to the DIR (returns
400). - You cannot delete the DIR (returns
409, blocked by theno_active_claimsprecondition). - You cannot re-submit the DIR with
POST /submit(returns409with the open claim IDs, blocked by theno_active_claimsprecondition). - To revise content while the claim is open, call
PUT /v2/dir/{dir_id}/infringement_updateon thesuspendedDIR (see “Fix-and-resubmit” below). This is the only way to re-vet during an open claim.
Claim lifecycle
API endpoints
Listing claims on a DIR
Getting a single claim
Contesting a claim
You can submit a contest more than once, the first submission moves the claim frompending to contested; later submissions append additional notes and documents to the same claim without changing status.
Contesting a
resolved claim returns 400.
Fix-and-resubmit a suspended DIR
While an infringement claim is open (pending or contested), Telnyx may pre-emptively move your DIR to suspended to halt branded calling. To recover without waiting for the claim to be resolved, use the dedicated PUT /v2/dir/{dir_id}/infringement_update endpoint to atomically apply your content fix and re-submit for vetting in one call. This endpoint requires an active (unresolved) claim and a suspended DIR (see “After the claim resolves” below).
- The DIR must have an active (unresolved) infringement claim.
- The DIR must be in
suspendedstatus. - All four certifications (
certify_no_infringement,certify_brand_is_accurate,certify_no_shaft_content,certify_ip_ownership) must be supplied astrue. infringement_resolution_notesis required (10-500 chars), explain how the edits resolve the claim.
display_name, logo_url, call_reasons) are all optional; send only the ones you’re changing. You can also attach supporting documents (up to 20, append-only) as proof that backs your fix, for example authorization or licensing paperwork. Each entry references a document_id from the Telnyx Documents API plus a document_type, and re-attaching a document already on the DIR is rejected. See the Infringement Claims guide for the full field table.
After the update, the DIR moves to submitted and goes through vetting again, even though the claim is still open. If the new content passes vetting, the DIR returns to verified and the claim can be resolved. If vetting rejects the changes, the DIR returns to suspended and you can update again. You can submit infringement_update multiple times while the claim is open.
Why the standardPATCH+POST /submitflow doesn’t work here:POST /submitis gated by the FSM’sno_active_claimsprecondition and returns409while a claim is stillpendingorcontested.PUT /infringement_updateis the only customer-callable endpoint that can move asuspended-with-open-claim DIR back into vetting; it bypasses theno_active_claimsgate by design. UsePATCH+POST /submitonly after Telnyx has marked the claimresolvedwithresolution = modified.resolution = rejectedauto-restores the DIR andresolution = upheldis terminal, neither requires a customerPATCH+/submit.
After the claim resolves
resolution = rejected: your DIR is automatically restored toverified; no action required. Branded calling resumes.resolution = upheld: your DIR ispermanently_rejectedand cannot be reused. To continue branded calling, create a new DIR with corrected content; you may reuse the same enterprise.resolution = modified: readresolution_notesfor the required content edits, thenPATCHthe DIR andPOST /submit(theno_active_claimsgate is now open because the claim isresolved).
API Reference (Calling)
Call Control Applications
- List call control applications: Return a list of call control applications.
- Create a call control application: Create a call control application.
- Retrieve a call control application: Retrieves the details of an existing call control application.
- Update a call control application: Updates settings of an existing call control application.
- Delete a call control application: Deletes a call control application.
Call Information
- List all active calls for given connection: Lists all active calls for given connection. Acceptable connections are either SIP connections with webhook_url or xml_request_url, call control or texml. Retu…
- Retrieve a call status: Returns the status of a call (data is available 10 minutes after call ended).
Debugging
- List call events: Filters call events by given filter parameters. Events are ordered by
occurred_at. If filter forleg_idorapplication_session_idis not present, it only…
Call Commands
- Dial: Dial a number or SIP URI from a given connection. A successful response will include a
call_leg_idwhich can be used to correlate the command with subsequent… - Answer call: Answer an incoming call. You must issue this command before executing subsequent commands on an incoming call.
- Bridge calls: Bridge two call control calls.
- Start AI Assistant: Start an AI assistant on the call.
- Join AI Assistant Conversation: Add a participant to an existing AI assistant conversation. Use this command to bring an additional call leg into a running AI conversation.
- Stop AI Assistant: Stop an AI assistant on the call.
- Add messages to AI Assistant: Add messages to the conversation started by an AI assistant on the call.
- Start Conversation Relay: Start a Conversation Relay session on an active call. Conversation Relay connects the call audio to your WebSocket so your application can exchange realtime me…
- Stop Conversation Relay: Stop the active Conversation Relay session on a call.
- Update client state: Updates client state
- Enqueue call: Put the call in a queue.
- Forking start: Call forking allows you to stream the media from a call to a specific target in realtime.
- Forking stop: Stop forking a call.
- Gather: Gather DTMF signals to build interactive menus.
- Gather stop: Stop current gather.
- Gather using AI: Gather parameters defined in the request payload using a voice assistant.
- Gather using audio: Play an audio file on the call until the required DTMF signals are gathered to build interactive menus.
- Gather using speak: Convert text to speech and play it on the call until the required DTMF signals are gathered to build interactive menus.
- Hangup call: Hang up the call.
- Reject a call: Reject an incoming call.
- Remove call from a queue: Removes the call from a queue.
- Play audio URL: Play an audio file on the call. If multiple play audio commands are issued consecutively,
- Stop audio playback: Stop audio being played on the call.
- Recording start: Start recording the call. Recording will stop on call hang-up, or can be initiated via the Stop Recording command.
- Recording stop: Stop recording the call.
- Record resume: Resume recording the call.
- Record pause: Pause recording the call. Recording can be resumed via Resume recording command.
- Send DTMF: Sends DTMF tones from this leg. DTMF tones will be heard by the other end of the call.
- SIP Refer a call: Initiate a SIP Refer on a Call Control call. You can initiate a SIP Refer at any point in the duration of a call.
- SIPREC start: Start siprec session to configured in SIPREC connector SRS.
- SIPREC stop: Stop SIPREC session.
- Speak text: Convert text to speech and play it back on the call. If multiple speak text commands are issued consecutively, the audio files will be placed in a queue awaiti…
- Streaming start: Start streaming the media from a call to a specific WebSocket address or Dialogflow connection in near-realtime. Audio will be delivered as base64-encoded RTP…
- Streaming stop: Stop streaming a call to a WebSocket.
- Noise Suppression Start (BETA)
- Noise Suppression Stop (BETA)
- Switch supervisor role: Switch the supervisor role for a bridged call. This allows switching between different supervisor modes during an active call
- Transcription start: Start real-time transcription. Transcription will stop on call hang-up, or can be initiated via the Transcription stop command.
- Transcription stop: Stop real-time transcription.
- Transfer call: Transfer a call to a new destination. If the transfer is unsuccessful, a
call.hangupwebhook for the other call (Leg B) will be sent indicating that the tran…
Callbacks
- Call Answered
- Call Deepfake Detection Error
- Call Deepfake Detection Result
- Call Initiated
- Call Streaming Failed
- Call Streaming Started
- Call Streaming Stopped
- Call Bridged
- Call Conversation Ended
- Call Conversation Insights Generated
- Call Enqueued
- Call Left Queue
- Call Fork Started
- Call Fork Stopped
- Call Dtmf Received
- Call Gather Ended
- Call AI Gather Ended
- Call AI Gather Message History Updated
- Call AI Gather Partial Results
- Call Playback Ended
- Call Playback Started
- Call Hangup
- Call Recording Saved
- Call Speak Ended
- Call Recording Error
- Call Recording Transcription Saved
- Call Refer Completed
- Call Refer Failed
- Call Refer Started
- Call Siprec Failed
- Call Siprec Started
- Call Siprec Stopped
- Call Speak Started
- Transcription
- Call Machine Detection Ended
- Call Machine Greeting Ended
- Call Machine Premium Detection Ended
- Call Machine Premium Greeting Ended
- Conference Created
- Conference Ended
- Conference Floor Changed
- Conference Participant Joined
- Conference Participant Left
- Conference Participant Playback Ended
- Conference Participant Playback Started
- Conference Participant Speak Ended
- Conference Participant Speak Started
- Conference Playback Ended
- Conference Playback Started
- Conference Recording Saved
- Conference Speak Ended
- Conference Speak Started
- TeXML AI Gather: Webhook sent when AI Gather completes with transcription results.
- TeXML Call AMD: Webhook sent when Answering Machine Detection (AMD) completes during a TeXML call.
- TeXML Call Answered: Webhook sent when a TeXML call is answered.
- TeXML Call Completed: Webhook sent when a TeXML call is completed.
- TeXML Call DTMF: Webhook sent when a DTMF digit is received during a TeXML call.
- TeXML Call Initiated: Webhook sent when a TeXML call is initiated.
- TeXML Call Ringing: Webhook sent when a TeXML call is ringing.
- TeXML Gather: Webhook sent when a Gather command completes (sent to the action URL).
- TeXML HTTP Request: Webhook sent as response to an HTTP Request instruction.
- TeXML Refer Status: Webhook sent for SIP REFER status updates.
- TeXML Conference End: Webhook sent when a TeXML conference ends.
- TeXML Conference Join: Webhook sent when a participant joins a TeXML conference.
- TeXML Conference Leave: Webhook sent when a participant leaves a TeXML conference.
- TeXML Conference Speaker: Webhook sent when a participant starts or stops speaking in a TeXML conference.
- TeXML Conference Start: Webhook sent when a TeXML conference starts.
- TeXML Recording Completed: Webhook sent when a recording is completed during a TeXML call (triggered by recordingStatusCallbackEvent).
- TeXML Recording In-Progress: Webhook sent when a recording starts during a TeXML call (triggered by recordingStatusCallbackEvent).
- TeXML Transcription: Webhook sent when a recording transcription is completed.
- TeXML SIPREC: Webhook sent for SIPREC session status updates.
- TeXML Stream: Webhook sent for media streaming status updates.
- TeXML Queue: Webhook sent for queue status events (triggered by Enqueue command waitUrl).
Conference Commands
- List conferences: Lists conferences. Conferences are created on demand, and will expire after all participants have left the conference or after 4 hours regardless of the number…
- Create conference: Create a conference from an existing call leg using a
call_control_idand a conference name. Upon creating the conference, the call will be automatically bri… - Retrieve a conference: Retrieve an existing conference
- Hold conference participants: Hold a list of participants in a conference call
- Join a conference: Join an existing call leg to a conference. Issue the Join Conference command with the conference ID in the path and the
call_control_idof the leg you wish t… - Leave a conference: Removes a call leg from a conference and moves it back to parked state.
- Mute conference participants: Mute a list of participants in a conference call
- Play audio to conference participants: Play audio to all or some participants on a conference call.
- Conference recording pause: Pause conference recording.
- Conference recording resume: Resume conference recording.
- Conference recording start: Start recording the conference. Recording will stop on conference end, or via the Stop Recording command.
- Conference recording stop: Stop recording the conference.
- Speak text to conference participants: Convert text to speech and play it to all or some participants.
- Stop audio being played on the conference: Stop audio being played to all or some participants on a conference call.
- Unhold conference participants: Unhold a list of participants in a conference call
- Unmute conference participants: Unmute a list of participants in a conference call
- Update conference participant: Update conference participant supervisor_role
- End a conference: End a conference and terminate all active participants.
- Gather DTMF using audio prompt in a conference: Play an audio file to a specific conference participant and gather DTMF input.
- Send DTMF to conference participants: Send DTMF tones to one or more conference participants.
- List conference participants: Lists conference participants
- Retrieve a conference participant: Retrieve details of a specific conference participant by their ID or label.
- Update a conference participant: Update properties of a conference participant.
TeXML Applications
- List all TeXML Applications: Returns a list of your TeXML Applications.
- Creates a TeXML Application: Creates a TeXML Application.
- Retrieve a TeXML Application: Retrieves the details of an existing TeXML Application.
- Update a TeXML Application: Updates settings of an existing TeXML Application.
- Deletes a TeXML Application: Deletes a TeXML Application.
TeXML REST Commands
- Fetch multiple call resources: Returns multiple call resouces for an account. This endpoint is eventually consistent.
- Initiate an outbound call: Initiate an outbound TeXML call. Telnyx will request TeXML from the XML Request URL configured for the connection in the Mission Control Portal.
- Fetch a call: Returns an individual call identified by its CallSid. This endpoint is eventually consistent.
- Update call: Update TeXML call. Please note that the keys present in the payload MUST BE formatted in CamelCase as specified in the example.
- Initiate an outbound AI call: Initiate an outbound AI call with warm-up support. Validates parameters, builds an internal TeXML with an AI Assistant configuration, encodes instructions into…
- List conference resources: Lists conference resources.
- Fetch a conference resource: Returns a conference resource.
- Update a conference resource: Updates a conference resource.
- List conference participants: Lists conference participants
- Dial a new conference participant: Dials a new conference participant
- Get conference participant resource: Gets conference participant resource
- Update a conference participant: Updates a conference participant
- Delete a conference participant: Deletes a conference participant
- Fetch multiple recording resources: Returns multiple recording resources for an account.
- Fetch recording resource: Returns recording resource identified by recording id.
- Delete recording resource: Deletes recording resource identified by recording id.
- Fetch recordings for a call: Returns recordings for a call identified by call_sid.
- Request recording for a call: Starts recording with specified parameters for call idientified by call_sid.
- Update recording on a call: Updates recording resource for particular call.
- List conference recordings: Lists conference recordings
- Fetch recordings for a conference: Returns recordings for a conference identified by conference_sid.
- List recording transcriptions: Returns multiple recording transcription resources for an account.
- Fetch a recording transcription resource: Returns the recording transcription resource identified by its ID.
- Delete a recording transcription: Permanently deletes a recording transcription.
- Request siprec session for a call: Starts siprec session with specified parameters for call idientified by call_sid.
- Updates siprec session for a call: Updates siprec session identified by siprec_sid.
- Start streaming media from a call.: Starts streaming media from a call to a specific WebSocket address.
- Update streaming on a call: Updates streaming resource for particular call.
- List queue resources: Lists queue resources.
- Create a new queue: Creates a new queue resource.
- Fetch a queue resource: Returns a queue resource.
- Update a queue resource: Updates a queue resource.
- Delete a queue resource: Delete a queue resource.
- Create a TeXML secret: Create a TeXML secret which can be later used as a Dynamic Parameter for TeXML when using Mustache Templates in your TeXML. In your TeXML you will be able to u…
Connections
- List connections: Returns a list of your connections irrespective of type.
- Retrieve a connection: Retrieves the high-level details of an existing connection. To retrieve specific authentication information, use the endpoint for the specific connection type.
Credential Connections
- List credential connections: Returns a list of your credential connections.
- Create a credential connection: Creates a credential connection.
- Retrieve a credential connection: Retrieves the details of an existing credential connection.
- Update a credential connection: Updates settings of an existing credential connection.
- Delete a credential connection: Deletes an existing credential connection.
- Check a Credential Connection Registration Status: Checks the registration_status for a credential connection, (
registration_status) as well as the timestamp for the last SIP registration event (`registration…
IPs
- List Ips: Get all IPs belonging to the user that match the given filters.
- Create an Ip: Create a new IP object.
- Retrieve an Ip: Return the details regarding a specific IP.
- Update an Ip: Update the details of a specific IP.
- Delete an Ip: Delete an IP.
IP Connections
- List Ip connections: Returns a list of your IP connections.
- Create an Ip connection: Creates an IP connection.
- Retrieve an Ip connection: Retrieves the details of an existing ip connection.
- Update an Ip connection: Updates settings of an existing IP connection.
- Delete an Ip connection: Deletes an existing IP connection.
FQDNs
- List FQDNs: Get all FQDNs belonging to the user that match the given filters.
- Create an FQDN: Create a new FQDN object.
- Retrieve an FQDN: Return the details regarding a specific FQDN.
- Update an FQDN: Update the details of a specific FQDN.
- Delete an FQDN: Delete an FQDN.
FQDN Connections
- List FQDN connections: Returns a list of your FQDN connections.
- Create an FQDN connection: Creates a FQDN connection.
- Retrieve an FQDN connection: Retrieves the details of an existing FQDN connection.
- Update an FQDN connection: Updates settings of an existing FQDN connection.
- Delete an FQDN connection: Deletes an FQDN connection.
UAC Connections
- List UAC connections: Returns a list of your UAC connections. A UAC (User Agent Client) Connection registers Telnyx to your PBX — the opposite of a standard SIP trunk, where the PBX…
- Create a UAC connection: Creates a UAC connection. A UAC (User Agent Client) Connection registers Telnyx to your PBX — the opposite of a standard SIP trunk, where the PBX registers to…
- Retrieve a UAC connection: Retrieves the details of an existing UAC connection.
- Update a UAC connection: Updates settings of an existing UAC connection.
- Delete a UAC connection: Deletes an existing UAC connection.
- Check a UAC Connection Registration Status: Checks the registration status for a UAC connection (
registration_status) as well as the timestamp for the last SIP registration event (`registration_status_… - SIP Registration Status: Returns the live SIP registration state of a UAC connection: whether it is currently registered, when it last registered, and the last response Telnyx received…
Outbound Voice Profiles
- Get all outbound voice profiles: Get all outbound voice profiles belonging to the user that match the given filters.
- Create an outbound voice profile: Create an outbound voice profile.
- Retrieve an outbound voice profile: Retrieves the details of an existing outbound voice profile.
- Updates an existing outbound voice profile.: Updates an existing outbound voice profile.
- Delete an outbound voice profile: Deletes an existing outbound voice profile.
Dialogflow Integration
- Retrieve stored Dialogflow Connection: Return details of the Dialogflow connection associated with the given CallControl connection.
- Create a Dialogflow Connection: Save Dialogflow Credentiails to Telnyx, so it can be used with other Telnyx services.
- Update stored Dialogflow Connection: Updates a stored Dialogflow Connection.
- Delete stored Dialogflow Connection: Deletes a stored Dialogflow Connection.
External Connections
- List all External Connections: This endpoint returns a list of your External Connections inside the ‘data’ attribute of the response. External Connections are used by Telnyx customers to sea…
- Creates an External Connection: Creates a new External Connection based on the parameters sent in the request. The external_sip_connection and outbound voice profile id are required. Once cre…
- Retrieve an External Connection: Return the details of an existing External Connection inside the ‘data’ attribute of the response.
- Update an External Connection: Updates settings of an existing External Connection based on the parameters of the request.
- Deletes an External Connection: Permanently deletes an External Connection. Deletion may be prevented if the application is in use by phone numbers, is active, or if it is an Operator Connect…
- List all civic addresses and locations: Returns the civic addresses and locations from Microsoft Teams.
- Retrieve a Civic Address: Return the details of an existing Civic Address with its Locations inside the ‘data’ attribute of the response.
- Update a location’s static emergency address
- List all phone numbers: Returns a list of all active phone numbers associated with the given external connection.
- Retrieve a phone number: Return the details of a phone number associated with the given external connection.
- Update a phone number: Asynchronously update settings of the phone number associated with the given external connection.
- List all Releases: Returns a list of your Releases for the given external connection. These are automatically created when you change the
connection_idof a phone number that i… - Retrieve a Release request: Return the details of a Release request and its phone numbers.
- List all Upload requests: Returns a list of your Upload requests for the given external connection.
- Creates an Upload request: Creates a new Upload request to Microsoft teams with the included phone numbers. Only one of civic_address_id or location_id must be provided, not both. The ma…
- Refresh the status of all Upload requests: Forces a recheck of the status of all pending Upload requests for the given external connection in the background.
- Get the count of pending upload requests: Returns the count of all pending upload requests for the given external connection.
- Retrieve an Upload request: Return the details of an Upload request and its phone numbers.
- Retry an Upload request: If there were any errors during the upload process, this endpoint will retry the upload request. In some cases this will reattempt the existing upload request,…
- List all log messages: Retrieve a list of log messages for all external connections associated with your account.
- Retrieve a log message: Retrieve a log message for an external connection associated with your account.
- Dismiss a log message: Dismiss a log message for an external connection associated with your account.
- Refresh Operator Connect integration: This endpoint will make an asynchronous request to refresh the Operator Connect integration with Microsoft Teams for the current user. This will create new ext…
Call Recordings
- List all call recordings: Returns a list of your call recordings.
- Retrieve a call recording: Retrieves the details of an existing call recording.
- Delete a call recording: Permanently deletes a call recording.
- Delete a list of call recordings: Permanently deletes a list of call recordings.
- List all recording transcriptions: Returns a list of your recording transcriptions.
- Retrieve a recording transcription: Retrieves the details of an existing recording transcription.
- Delete a recording transcription: Permanently deletes a recording transcription.
- Retrieve a stored credential: Returns the information about custom storage credentials.
- Create a custom storage credential: Creates a custom storage credentials configuration.
- Update a stored credential: Updates a stored custom credentials configuration.
- Delete a stored credential: Deletes a stored custom credentials configuration.
Media Storage API
- List uploaded media: Returns a list of stored media files.
- Upload media: Upload media file to Telnyx so it can be used with other Telnyx services
- Retrieve stored media: Returns the information about a stored media file.
- Update stored media: Updates a stored media file.
- Deletes stored media: Deletes a stored media file.
- Download stored media: Downloads a stored media file.
Credentials
- List all credentials: List all On-demand Credentials.
- Create a credential: Create a credential.
- Get a credential: Get the details of an existing On-demand Credential.
- Update a credential: Update an existing credential.
- Delete a credential: Delete an existing credential.
Access Tokens
- Create an Access Token.: Create an Access Token (JWT) for the credential.
Push Credentials
- List mobile push credentials: List mobile push credentials
- Creates a new mobile push credential: Creates a new mobile push credential
- Retrieves a mobile push credential: Retrieves mobile push credential based on the given
push_credential_id - Deletes a mobile push credential: Deletes a mobile push credential based on the given
push_credential_id
Voice SDK Stats
- List Voice SDK call reports: Returns paginated raw call report stats JSON payloads stored for the authenticated user. The user is derived from Telnyx authentication, not from request param…
- Retrieve Voice SDK call reports by call ID: Returns raw call report stats JSON payloads stored for the authenticated user and
call_id. The user is derived from Telnyx authentication, not from request p…
Enterprises
- List enterprises: Return the enterprises you own, paginated. The default page size is 20; the maximum is 250.
- Create an enterprise: Create the legal entity (enterprise) that represents your business on the Telnyx platform.
- Get an enterprise: Retrieve a single enterprise by id. Returns
404if the id does not exist or does not belong to your account. - Replace an enterprise: Replace the enterprise’s mutable fields. Only mutable fields may be sent. Server-assigned and immutable fields (
id,record_type,created_at,updated_at… - Delete an enterprise: Soft-delete an enterprise.
- Activate Branded Calling on an enterprise: Branded Calling is a paid product that must be activated on each enterprise. Activation is idempotent:
Display Identity Records
- List DIRs in an enterprise: Return the DIRs (Display Identity Records) belonging to a single enterprise. Pagination is JSON:API style (
page[number],page[size], max 250). Supports `fi… - Create a Display Identity Record (DIR): Create a new DIR under the given enterprise. The DIR starts in
draftstatus; it must be submitted (POST .../submit) and approved by Telnyx before any phone… - List all DIRs across your enterprises: Returns every DIR (Display Identity Record) you own, across all of your enterprises, as a single list. Pagination is JSON:API style (
page[number], `page[size… - Get a DIR by id: Returns a single DIR by id. The enterprise is resolved server-side from the DIR id. Returns
404if the DIR does not exist or is not yours. - Update a DIR: Edit a DIR. DIRs in
draft,rejected,unsuccessful, orsuspendedcan be edited freely: PATCH is a pure edit,statusis never changed, and you re-vet b… - Delete a DIR: Delete a DIR. Failure modes:
400if a child phone number is in a non-deletable status,409if the DIR has an unresolved infringement claim,404if the DI… - Submit a DIR for vetting: Submit a DIR for vetting. Sends the DIR back through the vetting cycle from any non-terminal status. When re-submitting from
suspendedorexpired, the DIR’… - Render the Branded Calling LOA for a DIR: Generate a pre-filled Letter of Authorization (LOA) PDF for a DIR. Enterprise identity (legal name, DBA, address, contact, website, tax id) and the DIR display…
Reference Data
- List supported DIR document types: Reference list of
document_typevalues accepted byDirCreateRequest.documents[].document_typeand the infringement-contest endpoint. Each entry has a stabl… - List standard call reasons: Telnyx maintains a library of pre-vetted call-reason phrases (e.g. “Appointment reminders”, “Billing inquiries”) that carry through DIR vetting smoothly. You c…
- Validate a list of call reasons: Check up to 10 candidate
call_reasonsstrings against Telnyx’s vetting heuristics before sending them on a DIR create or update. The endpoint flags strings t…
Comments
- List comments on a DIR: List the comments on a DIR. The enterprise is resolved server-side from the DIR id.
- Post a comment on a DIR: Post a customer comment on a DIR (for example, to respond to reviewer notes). Send only
content(1–5000 chars) and an optionalparent_comment_id; the serve…
Phone Numbers
- List phone numbers attached to a DIR: List the phone numbers registered under a DIR. The enterprise is resolved server-side from the DIR id.
- Add phone numbers to a DIR: Register phone numbers under a DIR. The enterprise is resolved server-side from the DIR id. Same body, failure modes, and batch semantics whichever path form y…
- Remove phone numbers from a DIR: Deregister phone numbers from a DIR. The enterprise is resolved server-side from the DIR id. Returns a partial-success envelope.
Phone Number Batches
- List phone-number batches for a DIR: List the phone-number batches submitted under a DIR. The enterprise is resolved server-side from the DIR id.
- Get a phone-number batch: Get a single phone-number batch by id. The enterprise is resolved server-side from the DIR id.
Infringement Claims
- List infringement claims for a DIR: Return the trademark or copyright claims filed against this DIR. Each claim’s
statusispending(newly filed; DIR auto-suspended),contested(you have su… - Update a DIR to resolve an infringement concern: Push a fix for a DIR that is
suspendedwith an open infringement claim back into vetting.POST /dir/{dir_id}/submitis blocked while a claim is open, so th… - Get an infringement claim: Retrieve a single claim by id. Returns
404if the claim does not exist or is not against a DIR you own. - Contest an infringement claim: Submit a written response and supporting documents disputing the claim. The first call moves the claim from
pendingtocontested; subsequent calls append s…
Terms of Service
- Agree to the Branded Calling Terms of Service: Records the authenticated user’s agreement to the current Branded Calling ToS. No body required. Idempotent - re-calling after agreement is a no-op and returns…
- Get Terms of Service information: Returns the available Terms of Service agreements (product, current version, terms URL, effective date). Omit
product_typeto return all products; pass it to… - Get the calling user’s Terms of Service status: Returns whether the authenticated user has agreed to the current Terms of Service for the product given by
product_type. Used during onboarding to decide whe… - List the calling user’s Terms of Service agreements: Returns the Terms of Service agreements the authenticated user has on file. Each entry records the version agreed to and when. Most users only have one agreeme…
- Get a Terms of Service agreement by id: Retrieve a single ToS agreement record. Returns
404if the agreement does not exist or does not belong to the authenticated user.