Voice AI · Internal build

A phone call is a latency budget with a conversation inside it.

Text agents get to think. A voice agent has roughly a second before the silence sounds wrong and the person on the other end says “hello?”. Everything in this build — the model choice, the speech cache, the turn handling — is spending that budget.

Voice AI · Telephony · SheetFlow internal build

Internal build — no public deployment.

A telephony service that answers Twilio webhooks and places real calls. Exposing it publicly would mean anyone could make it dial a number, so it is not hosted for demonstration.

src/server.js — 458 lines
Eight endpoints covering the full call lifecycle: initiation, greeting, each spoken turn, no-response handling, call status and audio delivery.
src/ai.js — 177 lines
Builds the conversation prompt from business configuration and drives a four-phase call structure — opener, discovery, bridge, book — with explicit end and booked signals.
src/tts.js — 100 lines
Speech synthesis with an in-memory audio cache served from a dedicated endpoint, expiring on a five-minute TTL swept every minute.
src/sheets.js — 98 lines
Writes the outcome of every call — timestamp, name, phone, reason, what the person said — to a spreadsheet log.
railway.json · Procfile · DEPLOY-NOW.md
Deployment configuration and a written runbook; the project was prepared for hosting rather than left as a script.
The problem

What the build had to solve.

  • A synthesised voice that pauses too long stops sounding like a person, and the call is lost in the first few seconds.

  • Telephony is stateful and HTTP is not — each spoken turn arrives as a separate webhook with no memory of the last.

  • A call that goes well and is not written down anywhere has produced nothing.

Architecture

How the work moves through it.

  1. Dial

    Contacts are read from a CSV and placed as outbound calls, each carrying its own reason for calling into the conversation.

    • Contact list
    • Twilio outbound
    • Per-call context
  2. Converse

    Each turn arrives as a webhook: speech is transcribed by the telephony layer, answered by the language model, and spoken back.

    • Speech capture
    • Language model turn
    • Session store
  3. Speak

    Replies are synthesised to audio, cached in memory and served from a URL the telephony platform plays, rather than re-generated per playback.

    • Neural TTS
    • In-memory cache
    • Audio endpoint
  4. Record

    The call ends on an explicit end or booked signal, and the outcome is appended to a spreadsheet log with what the person actually said.

    • End / booked signals
    • Call status webhook
    • Outcome log
The build

What it is made of.

Every row was read off the source, not from a project brief. Line counts, versions and limits are the ones in the files listed above.

Runtime
Node.js with Express 5 — 1,487 lines across 11 modules
Telephony
Twilio programmable voice, outbound
Language model
OpenRouter, defaulting to GPT-4o-mini and switchable by environment variable
Speech
ElevenLabs Flash v2.5, with a text fallback when no key is configured
Logging
Spreadsheet call log — timestamp, name, number, reason, transcript summary
Deployment
Railway configuration, Procfile, and an optional tunnel for local testing
Engineering decisions

The choices, and why they went that way.

The model was chosen for time-to-first-token, not for reasoning

On a phone call the strongest model is the wrong model if it thinks for two seconds. The default is a small fast one, and the choice is written down in the source next to the alternatives it was picked over — so the next person changing it knows the constraint they are trading against.

Verify: The model constant carries a comment comparing three candidates on speed against naturalness, and reads from an environment variable so it can be changed without a code edit.

Synthesised audio is cached and served, not regenerated

The telephony platform fetches the audio it plays, and can fetch it more than once. Generating speech per fetch pays the synthesis latency again inside the call and bills for it twice. Caching in memory behind an audio endpoint means each utterance is synthesised once, with a short TTL because a call is over in minutes.

Verify: Generated audio is stored against an id and served from `/audio/:id`, with a five-minute expiry swept on a one-minute interval.

Missing speech credentials degrade to text, not to a dropped call

If synthesis is unavailable the call can still happen through the telephony platform’s own voice. Falling back keeps the appointment bookable at lower quality rather than failing the call outright, which is the right trade for a missed configuration.

Verify: The speech module returns a fallback text payload rather than throwing when no API key is present.

The conversation has explicit exit signals

A voice agent without a defined ending keeps talking, and an open-ended call is both a cost and a bad experience. The prompt structures the call into four phases and requires the model to emit an explicit end or booked marker, so the server decides when to hang up on a signal rather than on a guess.

Verify: The prompt defines opener, discovery, bridge and booking phases, and the server terminates the loop on the end and booked markers.

Business outcome

What we can prove, and what we cannot.

Not publicly disclosed.

No business outcome has been measured against a stated method and confirmed with this client, so no figure is published. We would rather show you the system and let you judge it than print a number nobody verified.

Questions

About this project.

What is the AI Voice Receptionist?
A SheetFlow internal build: a Node.js service that places outbound phone calls over Twilio, holds a natural conversation using a language model with neural speech synthesis, works towards booking a consultation, and logs the outcome of every call to a spreadsheet. It is not publicly hosted.
Why is there no live demo of the voice agent?
Because a public endpoint for a system whose function is to place phone calls is a system anyone can make dial any number, at our cost and under our caller ID. The deployment configuration exists and the service runs; it is not exposed for demonstration.
What business results has the AI Voice Receptionist produced?
Not publicly disclosed. No call-outcome measurement has been confirmed against a stated method, so no figure is claimed — including connection rates, conversation length or appointments booked.