Skip to main content

Voice Agent Provisioning

Summary

Provisioning spins up a new customer's phone line end-to-end: it orders a local number from Telnyx, creates a LiveKit SIP inbound trunk and dispatch rule for that number, writes a church_voice_agents row to the database, and validates the call path with a test ring. The entire flow is triggered automatically by the Stripe webhook when a customer purchases any voice plan, and falls back to a founder-email alert if automation fails. The single deployed LiveKit agent (churchwiseai-voice) is multi-tenant — it serves every church; routing happens inside session.py:resolve_route() keyed by the called phone number.

Flow

Phase tracker

  • Phase 1 — Telnyx primary for new customers; legacy Twilio numbers untouched (merged 2026-03-30)
  • Phase 2 — LiveKit Cloud managed agent; Stripe webhook triggers provisionVoiceLine automatically (merged 2026-04-04)
  • Phase 3 — Automated self-serve provisioning with founder-alert fallback (in progress)
  • Phase 4 — Customer self-service portal: pastor chooses area code, sees number before purchase (planned)

Code files

FileRole
src/lib/voice-provision.tsprovisionVoiceLine() — full automation: Telnyx order → LiveKit trunk → dispatch rule → DB write
src/app/api/admin/provision-number/route.tsManual override API: POST with token, churchId, areaCode
src/app/api/voice/fallback/route.tsTeXML webhook for the fallback number (+14697288326) — plays message, hangs up
voice-agent-livekit/session.pyresolve_route() — maps called number to church UUID via PHONE_REGISTRY dict then DB fallback
voice-agent-livekit/main.pyAgent entry point; references church_voice_agents for per-church config
voice-agent-livekit/scripts/setup_sip.pyManual SIP trunk + dispatch rule creation script (reference / recovery use)
voice-agent-livekit/verticals/church/agents.pyChurch-vertical agent types and coordinator logic
voice-agent-livekit/verticals/church/church_info.pychurch_voice_agents DB queries, per-church config loading
voice-agent-livekit/core/rag.pyKnowledge-base retrieval used during live calls

Tests

voice-live-call in knowledge/tests/registry.yaml is declared but not yet gated by CI. Before any provisioning code change, manually run the Playwright live-flow spec against the deployed preview URL and attach the artifact. "Build passes" does not substitute for a live test call.

Decisions

2026-03-25-voice-platform — LiveKit Cloud was chosen over self-hosted LiveKit and Railway to eliminate infrastructure management for a solo founder; managed scaling and built-in SIP gateway were decisive.

2026-03-30-telnyx-over-twilio — Telnyx is cheaper (~$1/mo + $0.005/min vs Twilio $1.15/mo + $0.0085/min) and connects via direct SIP to LiveKit without a TwiML bridge. Existing Twilio numbers were kept as-is; Telnyx is used for all new customer provisioning.

Gotchas

  • Main Twilio trunk ST_Xa3Bp9aixRFP is LOCKED. Never modify its numbers, auth, or dispatch rules. An agent removed + prefixes following unrelated advice and instantly broke all working Twilio lines. Only voice-agent-engineer agent type may touch LiveKit SIP infrastructure, with explicit founder approval.

  • Telnyx FQDN must use project ID, not project name. Correct SIP endpoint: 5u9xu5ysoly.sip.livekit.cloud:5060 (project ID). Using the name-based URL cwa-voice-9x077mph.sip.livekit.cloud returns "404 No trunk found." The working Telnyx FQDN connection is 2925216093662349036 ("LiveKit Inbound v2") — assign new numbers to this connection; do not create a new one.

  • LiveKit SIP inbound trunks must have NO authentication set. Telnyx FQDN connections send standard SIP INVITEs without credential headers. If the LiveKit trunk has auth_username/auth_password configured, LiveKit challenges the INVITE and rejects every call — callers hear silence or "not assigned." Security is provided by Telnyx owning the DID.

  • 555-prefix numbers are fiction and cannot receive calls. Pattern ^\+1\d{3}555\d{4}$ is NPA-reserved for movies/TV. Some demo church_voice_agents rows were seeded with these as placeholders. Before telling the founder to dial any demo number, query church_voice_agents.twilio_phone_number and check the pattern. Fake demos route via Demo Router at +14696152221 (US) or +13658254095 (CA) only.

  • twilio_phone_number column holds Telnyx numbers too. The column name is a historical artifact. It stores whatever provider's number is assigned; the value works correctly regardless of provider.

  • LiveKit CLI lives at C:\dev\lk.exe. Deploy command: lk agent deploy --project cwa-voice --silent. Secrets are not re-uploaded on deploy — they were set via --secrets-file .env at agent creation.

  • New customer numbers use Telnyx; legacy numbers stay on Twilio. Do not migrate Twilio numbers. The toll-free number (+18886030316) has ~20% connect rate on direct SIP — it uses a TwiML-to-SIP bridge via /api/voice/twiml.

  • Transport must be TCP, not UDP. LiveKit's SIP endpoint does not reliably accept UDP from Telnyx. This is set on the Telnyx FQDN connection and does not need to be changed per customer.

Current phone numbers

NumberChurchProviderLiveKit Trunk
+14144007103Medhanialem Ethiopian Evangelical ChurchTelnyxST_LWgmiBSwTk7P
+17473897673Melvindale Church of GodTelnyxST_3KMJ5YEjF2fF
+18886030316Sales (toll-free)TwilioST_jKtes8Md7dEZ
+14696152221Demo (US)TwilioST_jKtes8Md7dEZ
+13658254095Demo (CA)TwilioST_jKtes8Md7dEZ
+14697288326Company fallback (TeXML, not LiveKit)TelnyxN/A

Recent activity

Reconciler (Phase 4) will populate this automatically from PR merges.