Answers every call
Picks up on the first ring, day or night. Greetings are cached per clinic voice, so the first word plays at once.
Twilio and NetGSM over AsteriskVoice AI receptionist, engineered by Mert Ural
Mainway answers a clinic’s phone, books the appointment, and goes quiet the moment you cut in.
Six jobs a front desk does all day, run by one engine.
Picks up on the first ring, day or night. Greetings are cached per clinic voice, so the first word plays at once.
Twilio and NetGSM over AsteriskChecks real free time, books it, and checks again before it commits.
Google Calendar FreeBusyPrices, hours, doctors and listings come from your own data.
Postgres pgvectorReal speech over its voice stops it within 280 ms and clears the line. A quick “hıhı” or its own echo doesn’t.
Barge-in with playback epochsRepeated questions, “I don’t know” signals and the caller’s mood decide when to transfer.
Escalation engine, ~96 testsScores the lead, texts the caller, and lists what it couldn’t answer.
Post-call loopEvery arrow is a real hop between systems. Play it and watch the caller cut in.
Everything between the caller’s last word and Mainway’s first, drawn as a building section. Height is time.
ElevenLabs turns the first sentence into audio while Claude writes the next one. estimate
Writes the first sentence. 912 ms to the first token in a blind A/B. GPT-4o, Gemini and Groq wait behind circuit breakers.
The clinic’s prices, hours and doctors come back from pgvector. estimate
850 ms of quiet, then a Turkish end-of-sentence rule and the smart-turn model confirm you are done.
Runs while you are still talking: Asterisk passes 20 ms frames, Scribe v2 transcribes them live, Deepgram stands by.
850 ms is the live setting and 912 ms is a measured first-token time. Retrieval and voice are estimates. End to end on real calls it measured 1.8 to 2.7 s.
It was knowing when someone has finished talking, and stopping the moment they start again.
1794interruptTts(reason = 'unknown') { 1796 if (this.currentTtsAbort) this.currentTtsAbort.abort(); 1802 this.playbackEpoch++;old frames stop 1805 this._flushTxQueue();queue emptied 1808 this.twilioWs.send('clear' ...);line flushed 1813 // Remember partial sentence for context next turn 1814 if (this.currentTtsSpoken)open bug D-01 1815 this.interruptedSentence = this.currentTtsSpoken; 1817 this.state = 'listening';
Each sector gets its own prompt, its own fields and its own rules. These three also have demo personas.
Also templated: e-commerce, restaurants, tourism, logistics, finance and education.
The call ends, the work doesn’t. Each step runs on its own, and the last one feeds the next call.
The transcript and timings are saved.
call_messagesAn LLM grades outcome, intent and satisfaction against a rubric.
Gemini, JSON rubricA confirmation goes out automatically.
SMSQuestions it couldn’t answer are collected for the owner.
knowledge gapsThe owner answers once; it becomes an FAQ entry.
dashboardA sweep every 5 minutes puts it into search.
pgvectorMainway never had paying customers. It had a lot of tests instead.
One square per automated test. Four failures look time-zone related; one misses a 2 ms noise-filter budget.
| Model | First token | Wins |
|---|---|---|
| Gemini 3.5 Flash | 929 ms | 7 |
| Claude Haiku 4.5 | 912 ms | 2 |
| GPT-4o | 757 ms | 1 |
LLM only, ten rounds. The judge was also one of the contestants.
Real test calls with three or four friends on a Turkish number. The lit squares are the 68 calls still in the last backup, with 477 messages and 75 bookings.
Simulated customers talk to the production brain through an internal endpoint: 27 scenarios across 10 sectors, scored by an LLM judge as the median of three runs.
eval-call-sim.mjs, sector-live-audit.mjsFound while preparing this page. Each has a file and a line.
A cut-off sentence is not carried into the next turn on the streaming path.
voice-stream.js:1741Smart Turn keeps the first 8 s of long speech, so it may never hear how you finished.
smart-turn/app.py:66If a provider fails after it already streamed text, the fallback may answer a second time.
llm-stream.js:616When Smart Turn errors, Node waits 1.2 s instead of moving on.
smart-turn/app.py:91Every voice turn embeds the same text twice.
voice-stream.js:1160Setting a Sentry DSN crashes startup on v10.
lib/sentry.jsNo. It is a project I built and tested on real calls. It never had paying customers, and this page doesn’t pretend otherwise.
Not by phone. The server lease ended in October 2026. A browser demo is being built, and the section below shows how it will work.
The real calls ran in Turkish. The engine has a language mode, and the English demo line is part of the browser demo.
All of it: the voice engine, the AI layer, the dashboard and the infrastructure.
To the providers in the stack: the phone carrier, ElevenLabs and Deepgram for speech, and Anthropic, OpenAI or Google for the language model.
It still holds server details and keys that need cleaning before it goes public. I share it on request.
Pick a business and talk. The panel shows each decision while it happens.
This mockup plays a sample call. The real demo will use your microphone and end after 2 minutes.