{"slug": "build-an-ai-call-router-that-sends-callers-to-the-right-team", "title": "Build an AI Call Router That Sends Callers to the Right Team", "summary": "Telnyx has released an open-source AI-powered call router that uses natural language processing to route callers to the correct team, replacing traditional IVR menus. The Python Flask application integrates Telnyx Call Control and AI Inference to transcribe caller speech and classify intent using an LLM, then transfers the call accordingly. The project includes webhook verification for security and is available on GitHub.", "body_md": "Traditional IVRs make callers do the routing work.\n\nYou call a business, listen to a menu, remember the options, press a number, and hope you picked the right path. That works, but it is not how people naturally ask for help.\n\nMost callers already know what they want:\n\nThe `ai-powered-call-router`\n\nexample turns that sentence into the routing decision.\n\nCode: [https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-powered-call-router](https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-powered-call-router)\n\nThis is a Python Flask app that handles inbound calls with Telnyx Call Control and classifies caller intent with Telnyx AI Inference.\n\nThe flow looks like this:\n\n``` php\nInbound call\n  -> Telnyx sends a Call Control webhook\n  -> Flask verifies the webhook\n  -> app answers the call\n  -> app speaks a greeting\n  -> app gathers caller speech\n  -> AI classifies intent\n  -> app announces the transfer\n  -> Call Control transfers the caller\n```\n\nInstead of asking the caller to press buttons, the app asks what they need and routes based on their answer.\n\nThe example uses:\n\nThe source keeps the route table intentionally small:\n\n```\nROUTE_TABLE = {\n    \"billing\": \"+1XXXXXXXXXX\",\n    \"sales\": \"+1XXXXXXXXXX\",\n    \"support\": \"+1XXXXXXXXXX\",\n}\n```\n\nIn a real app, those destinations might be queues, agents, contact center flows, or PBX extensions.\n\nOnce the inbound call is answered, the app plays a greeting. After the greeting finishes, it starts speech capture using Call Control's AI gather action.\n\nThe important detail is that the app waits for the `call.speak.ended`\n\nevent before starting the gather. That avoids the greeting and the caller's first response overlapping.\n\nThe gather step produces a `call.ai_gather.ended`\n\nevent with the caller's utterance.\n\nThat text becomes the input to the intent classifier.\n\nThe app sends the caller's transcribed request to Telnyx AI Inference and asks the model to classify it into one of the supported routes.\n\nThe default model in the sample is:\n\n```\nmeta-llama/Llama-3.3-70B-Instruct\n```\n\nThe model does not need to write a long answer. It only needs to return a routing label such as:\n\n```\nbilling\nsales\nsupport\n```\n\nThat keeps the AI part narrow and practical. The LLM is not running the whole call center. It is doing one job: mapping natural language to a route.\n\nAfter intent classification, the app speaks a short announcement:\n\n```\nTransferring you to billing. Please hold.\n```\n\nThen it waits for that announcement to finish before calling the transfer action.\n\nThat makes the caller experience cleaner. They hear what is happening before the bridge is created.\n\nThe example uses a blind transfer: Telnyx dials the destination and connects the original caller once the destination answers.\n\nVoice automation should not trust random HTTP requests.\n\nThe app verifies inbound Telnyx webhooks with Ed25519 signature verification before processing the event:\n\n```\nevent = unwrap_with_ed25519(\n    request.get_data(),\n    request.headers,\n    key=TELNYX_PUBLIC_KEY,\n)\n```\n\nThat means call actions like answer, gather, and transfer only run after the app verifies the webhook came from Telnyx.\n\nClone the examples repo:\n\n```\ngit clone https://github.com/team-telnyx/telnyx-code-examples.git\ncd telnyx-code-examples/ai-powered-call-router\n```\n\nCreate a virtual environment and install dependencies:\n\n```\npython3 -m venv venv\nsource venv/bin/activate\npip install -r requirements.txt\n```\n\nCreate your `.env`\n\nfile:\n\n```\ncp .env.example .env\n```\n\nSet the required values:\n\n```\nTELNYX_API_KEY=<your_telnyx_api_key>\nTELNYX_PUBLIC_KEY=<your_telnyx_public_key>\nTELNYX_CONNECTION_ID=<your_call_control_application_id>\nAI_MODEL=meta-llama/Llama-3.3-70B-Instruct\nPORT=5000\n```\n\nThen run:\n\n```\npython app.py\n```\n\nExpose your local server with a tunnel and point your Telnyx Call Control Application webhook to:\n\n```\nhttps://<your-tunnel-domain>/webhook\n```\n\nThis is a good example of where AI is useful without making the system vague.\n\nThe caller still moves through a deterministic telephony flow:\n\nThe model only handles the messy human-language part.\n\nThat is the sweet spot for a lot of production AI apps: use the LLM where language is ambiguous, but keep the workflow itself explicit and observable.\n\nBefore using this with real callers, I would add:\n\nBut the core idea is simple: callers should be able to say what they need, and your app should route them without forcing them through a rigid menu.", "url": "https://wpnews.pro/news/build-an-ai-call-router-that-sends-callers-to-the-right-team", "canonical_source": "https://dev.to/sonam_50a41a4ced7e6b4f3fa/build-an-ai-call-router-that-sends-callers-to-the-right-team-1cpj", "published_at": "2026-08-31 21:43:03+00:00", "updated_at": "2026-08-31 22:23:05.648125+00:00", "lang": "en", "topics": ["artificial-intelligence", "natural-language-processing", "ai-products", "developer-tools"], "entities": ["Telnyx", "Llama 3.3 70B", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/build-an-ai-call-router-that-sends-callers-to-the-right-team", "markdown": "https://wpnews.pro/news/build-an-ai-call-router-that-sends-callers-to-the-right-team.md", "text": "https://wpnews.pro/news/build-an-ai-call-router-that-sends-callers-to-the-right-team.txt", "jsonld": "https://wpnews.pro/news/build-an-ai-call-router-that-sends-callers-to-the-right-team.jsonld"}}