<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harpreet Singh Seehra</title>
    <description>The latest articles on DEV Community by Harpreet Singh Seehra (@harpreetseehra).</description>
    <link>https://dev.to/harpreetseehra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4008129%2F20acf0fe-5aa4-4a60-8949-504da9f7967c.png</url>
      <title>DEV Community: Harpreet Singh Seehra</title>
      <link>https://dev.to/harpreetseehra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harpreetseehra"/>
    <language>en</language>
    <item>
      <title>Route Phone Calls to an AI Agent With the Telnyx Voice API</title>
      <dc:creator>Harpreet Singh Seehra</dc:creator>
      <pubDate>Mon, 29 Jun 2026 12:19:44 +0000</pubDate>
      <link>https://dev.to/harpreetseehra/route-phone-calls-to-an-ai-agent-with-the-telnyx-voice-api-11ej</link>
      <guid>https://dev.to/harpreetseehra/route-phone-calls-to-an-ai-agent-with-the-telnyx-voice-api-11ej</guid>
      <description>&lt;p&gt;Voice AI agents are transforming customer service, sales, and support. But before an AI can talk to a caller, you need the voice infrastructure layer — a way to receive inbound phone calls, control the call flow, and respond programmatically. Without this foundation, your AI model has no way to pick up the phone.&lt;/p&gt;

&lt;p&gt;Telnyx Call Control gives you this through webhooks. When someone calls your Telnyx number, your application receives events in real time and issues commands back — answer, speak, gather input, transfer, or hang up. This is the foundation every voice AI agent runs on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Call Control?
&lt;/h2&gt;

&lt;p&gt;Telnyx Call Control is a webhook-driven API for programmable voice. Instead of static IVR menus, your application receives HTTP events for every call state change and responds with commands.&lt;/p&gt;

&lt;p&gt;The event loop works like this: Telnyx sends a webhook to your application, your app processes the event, your app issues a Call Control command, and Telnyx sends the next event when that command completes. This cycle repeats for the life of the call.&lt;/p&gt;

&lt;p&gt;This event-driven pattern is what makes voice AI possible. Your app can insert AI inference — speech-to-text, LLM processing, text-to-speech — between receiving a caller's input and responding. The Call Control webhook loop gives you a hook into every moment of the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The call flow has three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A customer calls your Telnyx number.&lt;/strong&gt; Telnyx sends a &lt;code&gt;call.initiated&lt;/code&gt; webhook to your application with the caller's number, your number, and a &lt;code&gt;call_control_id&lt;/code&gt; you'll use for all subsequent commands on this call.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Your application answers and responds.&lt;/strong&gt; Your webhook handler calls the &lt;code&gt;answer&lt;/code&gt; action to connect the call, then &lt;code&gt;speak&lt;/code&gt; to play a text-to-speech message to the caller. Each command triggers the next webhook event when it completes — &lt;code&gt;call.answered&lt;/code&gt; confirms the call connected, &lt;code&gt;call.speak.ended&lt;/code&gt; confirms the TTS finished.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The call completes.&lt;/strong&gt; When the TTS finishes, Telnyx sends a &lt;code&gt;call.speak.ended&lt;/code&gt; event. Your app issues &lt;code&gt;hangup&lt;/code&gt; to end the call. The &lt;code&gt;call.hangup&lt;/code&gt; event confirms cleanup.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One webhook endpoint. A state machine driven by events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key API Calls
&lt;/h2&gt;

&lt;p&gt;Everything below works with any language or framework. All you need is the ability to receive HTTP requests and make HTTP requests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Answer an Inbound Call
&lt;/h3&gt;

&lt;p&gt;When you receive a &lt;code&gt;call.initiated&lt;/code&gt; webhook, answer the call with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.telnyx.com/v2/calls/&lt;span class="o"&gt;{&lt;/span&gt;call_control_id&lt;span class="o"&gt;}&lt;/span&gt;/actions/answer &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_TELNYX_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;call_control_id&lt;/code&gt; comes from the &lt;code&gt;call.initiated&lt;/code&gt; webhook payload. It's the handle you use to issue every subsequent command on this call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Speak to the Caller (TTS)
&lt;/h3&gt;

&lt;p&gt;Once the call is connected, play a text-to-speech message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.telnyx.com/v2/calls/&lt;span class="o"&gt;{&lt;/span&gt;call_control_id&lt;span class="o"&gt;}&lt;/span&gt;/actions/speak &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_TELNYX_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "payload": "Thank you for calling. Your call is important to us. Goodbye.",
    "voice": "female",
    "language_code": "en-US"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;payload&lt;/code&gt; field is the text to speak. The &lt;code&gt;voice&lt;/code&gt; field accepts &lt;code&gt;female&lt;/code&gt; or &lt;code&gt;male&lt;/code&gt;. The &lt;code&gt;language_code&lt;/code&gt; field controls the language and accent — &lt;code&gt;en-US&lt;/code&gt;, &lt;code&gt;en-GB&lt;/code&gt;, &lt;code&gt;es-ES&lt;/code&gt;, and others are supported. When playback finishes, Telnyx sends a &lt;code&gt;call.speak.ended&lt;/code&gt; webhook event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hang Up the Call
&lt;/h3&gt;

&lt;p&gt;When you're done, terminate the call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.telnyx.com/v2/calls/&lt;span class="o"&gt;{&lt;/span&gt;call_control_id&lt;span class="o"&gt;}&lt;/span&gt;/actions/hangup &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_TELNYX_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Telnyx sends a &lt;code&gt;call.hangup&lt;/code&gt; event to confirm the call has ended. The &lt;code&gt;hangup_reason&lt;/code&gt; field in the event payload tells you why the call terminated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Webhook Signature Verification
&lt;/h3&gt;

&lt;p&gt;Telnyx signs every webhook request with an Ed25519 signature. Your application should verify this signature before processing the event to ensure the request actually came from Telnyx. The Telnyx SDKs handle this automatically — in Python, for example, you call &lt;code&gt;client.webhooks.unwrap()&lt;/code&gt; with the raw request body and headers.&lt;/p&gt;

&lt;p&gt;This requires the &lt;code&gt;TELNYX_PUBLIC_KEY&lt;/code&gt; environment variable, which you can find in the &lt;a href="https://portal.telnyx.com" rel="noopener noreferrer"&gt;Mission Control Portal&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Telnyx
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Webhook-driven, not poll-driven.&lt;/strong&gt; Every call state change arrives as an HTTP event — &lt;code&gt;call.initiated&lt;/code&gt;, &lt;code&gt;call.answered&lt;/code&gt;, &lt;code&gt;call.speak.ended&lt;/code&gt;, &lt;code&gt;call.hangup&lt;/code&gt;. Your app stays in control without polling or long-lived connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full call control vocabulary.&lt;/strong&gt; Answer, speak, gather DTMF or speech, transfer, conference, record — one API covers the entire call lifecycle. The same webhook loop works whether you're building a simple greeting or a multi-turn AI agent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Private network infrastructure.&lt;/strong&gt; Telnyx operates a private global IP network. Voice traffic doesn't traverse the public internet, reducing latency and improving call quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No per-minute markup games.&lt;/strong&gt; Telnyx pricing is straightforward. You pay for what you use without inflated per-minute fees or hidden platform surcharges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Started
&lt;/h2&gt;

&lt;p&gt;A complete working example — a Python Flask application that implements webhook signature verification, Call Control event handling, text-to-speech, and error handling — is available in the Telnyx code examples repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/team-telnyx/telnyx-code-examples/tree/main/route-phone-calls-to-ai-agent-python" rel="noopener noreferrer"&gt;&lt;strong&gt;route-phone-calls-to-ai-agent-python&lt;/strong&gt; on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The example includes a webhook endpoint (&lt;code&gt;/webhooks/call&lt;/code&gt;), a state machine that answers inbound calls and plays a TTS greeting, and proper error handling for authentication, rate limiting, and API errors. Clone it, add your credentials, and you have a running voice webhook handler.&lt;/p&gt;

&lt;p&gt;To get started:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://telnyx.com/sign-up" rel="noopener noreferrer"&gt;Sign up for a Telnyx account&lt;/a&gt; if you don't have one.&lt;/li&gt;
&lt;li&gt;Buy a phone number and create a Call Control Application in the &lt;a href="https://portal.telnyx.com" rel="noopener noreferrer"&gt;Mission Control Portal&lt;/a&gt;, setting your webhook URL to point to your &lt;code&gt;/webhooks/call&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;Clone the example repo, set your &lt;code&gt;TELNYX_API_KEY&lt;/code&gt; and &lt;code&gt;TELNYX_PUBLIC_KEY&lt;/code&gt; environment variables, and run the app.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full API documentation is available at &lt;a href="https://developers.telnyx.com" rel="noopener noreferrer"&gt;developers.telnyx.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>api</category>
      <category>infrastructure</category>
    </item>
  </channel>
</rss>
