{"slug": "how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me", "title": "How I Built an AI Voicemail System in 118 Lines (And What Surprised Me)", "summary": "A developer built an AI voicemail transcription and forwarding system in 118 lines of Python, uncovering multiple bugs in the Telnyx code examples repo including incorrect API method names, wrong SMS sender fields, and a token budget issue with reasoning models. The project uses Telnyx for telephony and the Kimi-K2.6 model for summarization, and the developer shares lessons about reading example code skeptically and budgeting tokens for reasoning models.", "body_md": "Last weekend I got mad at voicemail. Not at any individual voicemail — at the entire concept. Someone calls, leaves a 30-second message, and then I have to remember to check it. By the time I do, the urgent ones are old news and the spam ones have wasted my attention. So I built an AI that listens for me.\n\nThis post is about the build — what I chose, what I got wrong, and the two specific decisions that turned a flaky demo into something I'm actually comfortable shipping.\n\nThe canonical code example is in the Telnyx code examples repo:\n\nTelnyx has a public repo of around 480 code examples. The vast majority are too complex for a six-minute demo. I needed something that was small enough to teach the pattern, real enough to be useful, and visual enough to work on camera.\n\nI picked `ai-voicemail-transcription-forwarding-python`\n\nbecause:\n\nI cloned the example, filled in my API key, and the AI part worked great. Then I tested the SMS delivery. It failed. Every time.\n\nThe bug: the `send_sms`\n\nfunction was passing the **caller's** phone number as the `from`\n\nfield. The owner's number was set as `to`\n\n. So the API was saying \"send an SMS from this random number I don't own, to this number.\" Telnyx (correctly) rejects that.\n\nThis was in the upstream `team-telnyx/telnyx-code-examples`\n\nrepo. It's listed as \"production-ready.\" It is not production-ready. It would never have sent a single SMS in production.\n\nI dug through the rest of the code and found twelve issues total. The takeaway was the same: **read example code skeptically, even from authoritative sources.**\n\nThis one took me a while. The upstream example used `client.calls.actions.record_start()`\n\nand `client.calls.actions.transcription_start()`\n\n. Neither of those methods exist in the current Telnyx SDK. The actual names are `start_recording()`\n\nand `start_transcription()`\n\n.\n\nEven worse: `start_recording()`\n\nhas a built-in `transcription`\n\nparameter. You can do recording + transcription in one call instead of two. The upstream example was doing it the hard way AND using wrong method names.\n\nThen there was the `language_code`\n\nparameter on the `speak()`\n\ncall. The SDK uses `language`\n\n, not `language_code`\n\n. The speak returned 200 but then a `call.speak.failed`\n\nwebhook arrived with a 400 \"not well-formed\" error. The greeting never played.\n\nThis was the sneakiest bug. I assumed the transcription would stream in chunks via `call.transcription`\n\nwebhooks while the caller was speaking. That's how the upstream example was written.\n\nIn reality, the transcription arrives as a single `call.recording.transcription.saved`\n\nwebhook AFTER the caller hangs up, with the full text in a `transcription_text`\n\nfield. Different event name, different payload structure, different timing.\n\nThe fix: the app now waits for the transcription on hangup instead of processing immediately. If the transcript arrives after the session is popped, it recreates the session and processes it.\n\nThe first version used `max_tokens=300`\n\nfor the LLM call. It worked in my unit tests. It failed in production. The AI Inference call returned, but the JSON got truncated mid-word, like `{\"priority\":\"urgent\",\"summary\":\"Sarah reports`\n\n. Why?\n\nBecause the model — `moonshotai/Kimi-K2.6`\n\n— has reasoning tokens. When you ask it to think step-by-step, the reasoning comes out of the same token budget as the answer. With `max_tokens=300`\n\n, my answer was getting cut off after the first ~50 tokens of actual JSON because Kimi had burned 250 tokens reasoning about whether it should return JSON.\n\nThe fix was bumping `max_tokens`\n\nto 1500. **Rule of thumb: when using reasoning models, budget 5-10x more tokens than the visible output needs.**\n\nThe upstream example used `voice=\"female\"`\n\nwhich is the basic TTS tier. It sounded robotic. I upgraded to `AWS.Polly.Joanna-Neural`\n\nwith `service_level=\"premium\"`\n\n— a natural, human-like voice. One parameter change, dramatic quality difference.\n\nA few things I'd change if I was starting over:\n\n`call.recording.saved`\n\nwebhook, so the audio is just sitting in Telnyx's storage with no way to retrieve it from my app.The hardest part wasn't the code. It was figuring out what the AI should actually decide. \"Urgent vs normal vs spam\" feels obvious, but the edge cases are where the value is:\n\nI haven't solved this. The next iteration would be a small eval set — twenty voicemails with my labels — and a prompt I tune against it.\n\nThis is the first of three apps I'm building for a YouTube series. The next one is an AI language tutor — call a phone number, practice a foreign language with an AI that adapts to your level. Same skeleton. By the third video, the audience will have seen the pattern three times and should be able to build anything on top of it.\n\nIf you want to build the voicemail yourself, the [repo](https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-voicemail-transcription-forwarding-python) has the full code. The state machine itself fits in one screen — the rest is error handling, logging, and JSON parsing defenses. Should take you 30 minutes including the inevitable debugging.", "url": "https://wpnews.pro/news/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me", "canonical_source": "https://dev.to/botoclock/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me-383i", "published_at": "2026-07-10 17:15:29+00:00", "updated_at": "2026-07-10 17:45:08.724194+00:00", "lang": "en", "topics": ["artificial-intelligence", "developer-tools", "ai-products"], "entities": ["Telnyx", "Kimi-K2.6", "AWS.Polly.Joanna-Neural", "moonshotai"], "alternates": {"html": "https://wpnews.pro/news/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me", "markdown": "https://wpnews.pro/news/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me.md", "text": "https://wpnews.pro/news/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me.txt", "jsonld": "https://wpnews.pro/news/how-i-built-an-ai-voicemail-system-in-118-lines-and-what-surprised-me.jsonld"}}