How to Build a Voice AI Agent with OpenAI's GPT-Live, Twilio Agent Connect, and TypeScript Twilio released a GPTLiveProvider in its open-source TypeScript SDK Twilio Agent Connect (v2.4.0+) that bridges Twilio Programmable Voice Media Streams directly to OpenAI's GPT-Live-1 speech-to-speech model, letting developers build inbound and outbound phone voice agents without custom WebSocket plumbing. The tutorial requires Node.js 22.13+, a Twilio phone number with Voice capability, and an OpenAI API key with GPT-Live access, and uses a declarative config interface where defaultSessionConfig is sent as GPT-Live's session.start payload with the model, instructions, and audio.format set to TWILIO_AUDIO_FORMAT_FOR_GPT_LIVE. How to Build a Voice AI Agent with OpenAI's GPT-Live, Twilio Agent Connect, and TypeScript Time to read: Written by Reviewed by "It works great in my testing script, but the second we put it on a real phone call, it falls apart." That's a common complaint once a voice AI demo meets production traffic. OpenAI's GPT-Live https://openai.com/index/introducing-gpt-live/ is a family of full-duplex speech-to-speech, or S2S, models. They separate the conversation and any necessary background work, allowing you to delegate to your own backend or an OpenAI hosted model. Twilio Agent Connect https://www.twilio.com/docs/conversations/agent-connect is Twilio's open-source TypeScript SDK for building voice and messaging AI agents, and we now ship a GPTLiveProvider that bridges Twilio Programmable Voice https://www.twilio.com/docs/voice Media Streams https://www.twilio.com/docs/voice/guides/media-streams-guides directly to GPT-Live-1 in the OpenAI API https://openai.com/index/introducing-gpt-live-1-in-the-api/ . It all works through a flexible, declarative config interface – you don’t need any custom WebSocket plumbing. In this tutorial, you'll use TypeScript and build a phone number that connects inbound callers to a GPT-Live-powered voice agent. It’ll greet the caller and the caller can ask it a question that triggers a tool call. Then, I’ll show you how to place an outbound call with Twilio and GPT-Live. While we build together, I’ll also show you other features like per-call customization, and you can explore from there. Let’s get started Prerequisites and common pitfalls to getting started prerequisites-and-common-pitfalls-to-getting-started - A free Twilio account - Sign up for an account here https://www.twilio.com/try-twilio . - A Twilio phone number with Voice capability - buy one from your Twilio Console https://1console.twilio.com/ . - An OpenAI API key from a project with GPT-Live access. - Node.js 22.13+ and the Twilio Agent Connect https://twilio.github.io/twilio-agent-connect-typescript/ SDK v2.4.0+ installed, along with dotenv npm install twilio-agent-connect dotenv . - A public HTTPS/WSS endpoint for local development — ngrok https://ngrok.com/ works well. Build the app build-the-app The full working example lives at getting started/examples/gpt-live https://github.com/twilio/twilio-agent-connect-typescript/tree/main/getting started/examples/gpt-live . Follow along below, or clone the repo and run that example directly. Step 1: Set up TAC and the Fastify server toc-heading-407bf5aa-5f27-4e47-ba99-3012cf2c08f6 Every TAC voice app starts with a Twilio Agent Connect instance and a VoiceChannel . VoiceChannel is provider-agnostic: the same class hosts Conversation Relay https://www.twilio.com/docs/voice/twiml/connect/conversationrelay , GPT Realtime, and GPT-Live, depending on which config you pass it. TACConfig.fromEnv reads its settings from environment variables. Create a .env file in your project root with TWILIO ACCOUNT SID and TWILIO AUTH TOKEN found on your Console dashboard https://console.twilio.com/ , TWILIO API KEY and TWILIO API SECRET from API keys & tokens , TWILIO PHONE NUMBER from Phone Numbers Manage Active Numbers , TWILIO VOICE PUBLIC DOMAIN your ngrok domain from the prerequisites step , and OPENAI API KEY , and the dotenv/config import above picks them up automatically. Step 2: Configure the GPT-Live session and greeting toc-heading-3456827a-1417-43a6-a86a-28446c5f72e8 defaultSessionConfig is sent as GPT-Live's session.start payload the moment the model connects. At minimum it needs the model, instructions the system prompt , and audio.format set to TWILIO AUDIO FORMAT FOR GPT LIVE . Setting welcomeInstruction makes the agent speak first instead of waiting for the caller, which is useful for any call where the caller doesn't know they've reached an AI agent yet. Step 3: Wire up a tool call toc-heading-5835064a-a695-4871-a2e3-43cb803f9257 GPT-Live doesn't call functions directly – instead, it delegates tool calls https://developers.openai.com/api/docs/guides/live-delegation either through Client Delegation where you need to build the delegation integration or through a Responses API model. In this tutorial, we’ll use Responses delegation https://developers.openai.com/api/docs/guides/live-delegation?delegation-mode=responses configure-responses-delegation . Any tool created with defineTool can be exposed this way: register it in tools: ... so Twilio Agent Connect can execute it, and separately list its schema under delegation.responses.tools so the model knows it exists. Keeping tool execution outside the real-time voice loop means your tool logic can be as slow or complex as it needs to be. Consider all the things you might include in your logic: a database lookup, an API call, or a business rule. The 3-second setTimeout in the code above makes the strength of this model visible: run the demo and the call keeps going while the tool runs. GPT-Live delegates the decision to call a tool to a Responses API model, then Twilio Agent Connect runs the actual TypeScript function and speaks back the result. And hopefully, that shows how straightforward OpenAI’s Responses delegation is. Of course,when you build your own agent, swap getWeather for a function that hits your own backend. For example, you might look up an order status, check appointment availability, or pull account details. All the same wiring applies without changing anything else here. Step 4: Wire up the server toc-heading-f5750e4c-7127-4285-b240-4a4378e70b4c TACServer mounts the TwiML endpoint at /twiml by default. Step 5: Point your Twilio number at the webhook toc-heading-2871d186-5f1d-456b-ac80-13c97d431480 With the server running behind a public tunnel like ngrok , tell Twilio where to send incoming calls: - In the Twilio Console, go to Phone Numbers Manage Active Numbers and select your number. - Under Voice Configuration, set "A call comes in" to Webhook, and enter https://