· Voice AI Gateway
Feasibility & delivery plan · Pilot → GA → Full scope

SoW analysis · technical review · delivery plan

Voice AI
Gateway

A full teardown of the SoW, a deep technical analysis of what it really demands — then how we would build it, who builds it, and by when.

1 · What the SoW asks 2 · Architectural choices 3 · Who builds it 4 · Timeline & run cost
Scoped against SoW v2.0 · incl. Amendments A & B · 29 Jul 2026
navigate · F fullscreen

What the analysis found

Buildable in-house — with one specialist hire.

The technical read splits the SoW cleanly: everything except the real-time media plane is work our existing Python, Next.js and DevOps engineers already do. The telephony layer is the one genuinely specialist piece — and it is also the heart of the product, so it gets a dedicated owner rather than a web team learning VoIP under deadline.

Peak 7
people, averaging 6 — of whom exactly one is a new hire
Month 3
live pilot on real traffic · GA month 5 · full SoW ~month 7
40–45
person-months of build effort across all four phases
1.5–2.5
FTE to operate it afterwards as a managed service
The commercial headline ◇ The AWS bill is a rounding error. AI engine minutes are the real cost line — so our pricing to the client must be built around per-minute economics, not infrastructure.

What the SoW actually asks for

Six jobs behind the “ISA proxy” analogy.

A real-time voice-AI middleware platform for BPO outbound dialing: it sits between client ViciDial/Asterisk dialers and AI voice engines.

+
01 · Gateway
Accept live audio from many dialers, resolve the tenant from SIP headers/IP, enforce per-tenant concurrency, isolate credentials & prompts. 403 unknown sources.

The SoW's “ISA proxy” layer. One entry point serves every client cluster, and the first thing it must do on each inbound call is work out whose call this is — before any audio is processed or any money is spent.

  • Tenant resolution — inbound SIP headers and source IP are matched against a tenant registry to bind the call to one workspace (Profile_A vs Profile_B in SoW language).
  • Hard isolation per tenant — credentials, billing keys, prompt text blocks, voice definitions and webhook targets live in separate logical partitions. Nothing crosses.
  • Concurrency quotas — each tenant has a channel ceiling (SoW example: 10 for Tenant A, 25 for Tenant B) plus a global software-wide cap. Enforced in Redis so the count is correct across processes.
  • Unauthorised sources — connections from unknown IPs are dropped immediately with a 403-equivalent signalling error, never partially processed.
  • Channel lifecycle — every accepted call becomes a lightweight non-blocking async task; on completion its state cache is purged and the slot returns to the pool.
Engineering read ◇ Solid async Python and Redis work — learnable and testable. The risk here is not difficulty, it is discipline: cross-tenant leakage is a trust-ending bug, so isolation gets automated tests in CI and is a pilot exit criterion.
+
02 · Triage
Within ~1.5s of answer: VAD + answering-machine detection. Machines → voicemail drop; IVR → DTMF; dead air → check-in then drop.

Every answered call is classified before the expensive AI leg is bridged. The SoW asks for a verdict inside ~1.5 seconds using streaming voice-activity detection alongside live transcription.

  • Answering machine / voicemail — intercept the long greeting, wait for the tone, play the voicemail drop, hang up fast.
  • Business IVR — detected and navigated out-of-band by issuing DTMF tones, rather than talking to a menu.
  • Dead air / silence — fire a check-in hook, then execute a clean drop if nothing comes back.
  • Live human confirmed — the only outcome that proceeds to the AI dialogue engine.
Why this is the commercial core ◇ In outbound BPO traffic 50–70% of connects are machines, IVRs or dead air. Because triage runs on our own near-free infrastructure, those calls never touch a paid engine minute — which roughly halves the engine bill and is what makes the managed-engine path viable at 500 channels.
Hardest part ◇ AMD accuracy is a tuning craft, not a library call. False positives hang up on real humans; false negatives burn engine spend. We measure it from pilot day one and agree a target with the client.
+
03 · Conversation
Low-latency STT→LLM→TTS with barge-in, silence handling (2.5s nudge), and qualification scored live against a checkpoint schema.

A bidirectional streaming pipeline: raw trunk audio becomes text, text feeds the LLM with the tenant's script and rules injected, and the reply is streamed back down the trunk as speech — continuously, not in turns.

  • Barge-in — when incoming audio energy crosses the human-speech threshold, the outbound stream stops immediately. Without this the bot talks over people and the call is lost.
  • Silence handling — a gentle “Hello, are you there?” after 2.5s of silence; terminate if a further ~3s passes with nothing.
  • Gated qualification — conversation checkpoints are tracked against a structured schema array, with compliance flags evaluated in real time to drive branching.
  • Per-tenant behaviour — script, voice clone and LLM temperament all come from the resolved tenant profile, injected at session start.
Buy, not build ◇ Sub-second voice loops are the entire business of Retell and Vapi. We integrate one behind our own adapter interface rather than rebuilding STT/LLM/TTS orchestration — which would add months of the highest-risk work with zero pilot value.
+
04 · Disposition
Qualified → SIP warm transfer into a ViciDial conference with a human closer. Otherwise tag NI/DNC, drop, purge and recycle the channel.

The commercial payload of the whole platform: a qualified conversation has to become a human-to-human call, and an unqualified one has to be recorded correctly in the client's dialer.

  • Qualified branch — hit the ViciDial conference API to bridge the call into the human closer queue, then drop the bot leg out of the stream so the prospect is left talking to a person.
  • Unqualified branch — call ViciDial's external status API to tag the lead NI or DNC, then disconnect the audio loop.
  • Session reset — purge the thread's state cache so no text memory leaks into the next call on that channel, then free the slot for the next dialer trigger.
Engineering read ◇ Moderate difficulty, but quirky legacy APIs. This is why a ViciDial lab from week 1 plus staging access to the client's real cluster are non-negotiable — API behaviour and Asterisk version compatibility are discovery items, not assumptions.
+
05 · Portal Amd A
Locked prompt templates with {{variable}} injection. RBAC support staff edit only campaign variables. Immutable audit: who, when, IP, before/after.

A deliberate separation between core codebase and day-to-day campaign changes, so a support agent adjusting today's promo can never break the system or see its internals.

  • Guardrail by design — master prompts are locked, immutable templates containing placeholders such as {{daily_campaign_update}} and {{dynamic_lead_criteria}}. Prompt internals, webhooks and billing structures are hidden from non-admin accounts.
  • Campaign requirements box — a plain-text field mapped straight to variable injection: support staff type daily script rules, active promos or targeted offers in plain English, and it propagates to active bots immediately.
  • Voice & accent controls — dropdowns to swap voice clones, accent styles or synthetic engines (ElevenLabs, Cartesia) per tenant workspace.
  • Immutable activity log — every admin action records a high-precision UTC timestamp, the user's username / login email / origin IP, and the exact target campaign, variable modified and before & after values.
Sequencing note ◇ The portal UI arrives in phase 2, but the locked-template data model starts in phase 1 — variable injection has to exist before there is a screen to edit it. Audit is append-only and hash-chained so “immutable” is structural, not a policy promise.
+
06 · QA bot Amd B
Taps live calls without admin access, scores compliance (age, disclaimers, script) and files a ticket to the client CRM within 60s of hangup.

A second agent that monitors human agent conversations live and scores compliance — explicitly without needing root access to the client's call-recording servers.

Tap option 1ViciDial blind_monitor — the Non-Agent API silently joins an active agent session. Needs only a basic API user, not Level 9 admin. Our primary path.
Tap option 2SIP forking / SIPREC — real-time RTP duplication at the SBC, streaming split agent and customer feeds. Best quality, but assumes an SBC most ViciDial shops do not have.
Tap option 3Ghost agent — a headless WebRTC softphone joins the campaign conference as a silent muted listener. Fallback only.
  • Stereo transcription — streaming STT with the agent channel separated from the customer channel.
  • Rule evaluation — an LLM matches the live transcript against the target script: mandatory compliance lines, buyer requirements, qualification markers.
  • Compliance scoring — did age verification, medical-status checks and disclaimers actually happen? Met or missed, per requirement.
  • Ticket out — within 60 seconds of hangup, a compliance ticket with metrics, verified script markers and the full transcript is webhooked to the client CRM.
Costing note ◇ The QA bot meters on monitored human-agent hours, not bot calls — roughly $1.0–1.3 per monitored hour (stereo STT + LLM scoring). It should be quoted to the client as its own metered line.
+ Click any job for the technical detail behind it

Key decisions · made, with rationale

Four calls that set the whole shape.

Everything downstream — team, timeline and cost — follows from these. Each one was chosen to de-risk the launch without closing off the better long-run economics.

DecisionChoiceWhyDetail
D1AI engine strategy Hybrid via adapterChosen Launch on a managed engine (Retell or Vapi, decided by bake-off) behind our own interface. Fastest to pilot; keeps a later custom pipeline as a swap, not a rewrite. +

The SoW itself leaves this open — it names “Retell AI, Vapi, or raw custom pipelines”. Those are wildly different projects, so this was the first fork to close.

ChosenManaged engine now, behind an adapter interface. The engine is a swappable dependency, not a foundation.
Rejected AManaged engine forever — smallest build, but per-minute cost compounds indefinitely and we stay exposed to their pricing and concurrency limits at 500 channels.
Rejected BCustom STT/LLM/TTS from day one — best unit economics, but adds ~3–5 months of the hardest real-time audio engineering and is the highest-risk path for a team without VoIP experience.
  • Removes months of latency/barge-in work from the critical path — that is Retell and Vapi's entire business.
  • Shrinks the build to gateway + triage + policy + portal + QA bot: integration engineering our team already does.
  • Preserves the margin option: at 500 channels, self-orchestrating is worth $60–110k/month, reviewed at the phase-3 gate with real volumes.
What it costs us ◇ Roughly $0.08–0.14/min all-in while we are on a managed engine — treated as a pass-through-with-margin line, never absorbed.
D2Media entry architecture Own SIP media edgeShapes everything We present to the client as a plain SIP destination. Works with any ViciDial version, no client-side surgery, tenant identity lands on SIP headers, and triage stays on our metal. +

The single most consequential technical decision in the plan — it determines onboarding friction, security posture, and the engine bill.

Option A
not chosen
Direct AudioSocket. The SoW's literal suggestion: each client streams raw PCM from their Asterisk dialplan to our TCP endpoint. Least infrastructure for us — but it requires Asterisk 18+ (many ViciDial installs are older), needs invasive dialplan changes on every client box, sends unencrypted audio over the public internet, and turns each onboarding into a support project.
Option B
chosen
Our own SIP media edge (Kamailio/FreeSWITCH + RTPengine). ViciDial routes answered calls to us like it routes to any carrier. Works with any version, zero client-side surgery beyond one route entry, tenant identification lands naturally on SIP headers and source IP exactly as the SoW describes, and TLS/SRTP becomes possible.
Option C
later
B now, A later — direct AudioSocket returns as an opt-in low-latency route for clients already on modern Asterisk. A phase-3 menu item, not a launch dependency.
Commercial, not just technical ◇ Because triage runs on our edge before the engine leg is bridged, we filter machines and IVRs at near-zero cost. That single choice roughly halves the engine bill — the difference between the managed-engine path being viable or not at 500 channels.
D3Launch scale Pilot first: 25–50 chThen 100, then 500 Prove AMD accuracy and transfer flows on real traffic before capacity hardening. Earliest revenue, lowest risk. +

The SoW names 100 concurrent bots as “initial scale” and 500 as “target bulk scale”. We deliberately go live below both.

  • Pilot · month 3 — 1–2 tenants, 25–50 concurrent channels, supervised ramp with engineers watching calls and tuning AMD live.
  • GA · month 5 — 100-channel capability, load-tested, portal in the hands of support staff, security review passed.
  • Scale · month 7+ — validation toward 500 channels on a multi-instance edge, where engine concurrency becomes an enterprise negotiation.
Why not 100 at go-live ◇ It adds 2–3 weeks of load-testing and capacity hardening to the critical path before a single real call is handled — spending hardening effort on numbers we have not yet validated behaviour at. All three tiers are costed regardless.
D4Operating model Build + operateRecurring revenue We run it in production and onboard tenants. Adds an ops staffing tail and an on-call rotation that must be agreed before committing. +

Chosen over build-and-hand-over. It is the better commercial position, but it is a standing obligation, not a project with an end date.

  • Run-rate: 1.5–2.5 FTE after GA — 0.5 telephony, 0.5 backend, 0.5 DevOps/on-call amortised, 0.5–1 support and tenant onboarding, growing with tenant count.
  • On-call is real. Three people must be able to answer a 2 a.m. “calls aren't transferring” page: the telephony engineer, a senior Python dev, and DevOps. That is a rotation drawn from the build team.
  • We carry the infrastructure bill and, depending on the commercial answer, possibly the engine contract too — which is one of the six open questions for the client.
Say it out loud ◇ Agree the on-call rotation with the team before committing to operate. A managed service sold without an answer to nights and weekends becomes an attrition problem in month 6.
+ Click any decision for the options considered and what was rejected

Architecture · the call path

Filter on our metal. Pay only for humans.

Client premisestheir kit, unchanged
+
ViciDial dialers
Client A · B · N — any version
  • their trunks dial, their carrier cost
  • onboarding = one route entry

Each client keeps running their own ViciDial/Asterisk cluster exactly as they do today. Nothing about their dialing, lead lists or carrier arrangements changes.

  • They dial, they pay the carrier. Trunk costs stay entirely client-side — our platform only ever receives calls that have already been answered.
  • Onboarding is one route entry — they point answered calls at our SIP address the way they would point at any carrier or agent group. No dialplan rewriting, nothing installed on their boxes.
  • Version-agnostic. Because we speak plain SIP rather than requiring Asterisk 18+ AudioSocket, older ViciDial installs work unchanged — the deciding factor in decision D2.
  • They are also the transfer destination — qualified calls come back to their human closer queues through the conference API.
Day-one dependency ◇ We need our own ViciDial lab (Vicibox on a cloud VM) from week 1, plus staging access to the client's real cluster. API quirks and version compatibility are discovery items, not assumptions.
SIP invite
+ RTP audio
Human closer queues
warm-transfer destination
  • bot leg drops, a person takes over
conference
bridge
Our platformthe call path · we build this
1+
SIP media edge
Kamailio · RTPengine
  • resolve tenant — headers / IP
  • allowlist → 403 unknown
  • TLS / SRTP

The SoW's “ISA-style policy proxy”, made concrete. We run a real telephony stack so that to every client we are simply a SIP destination — and so that all policy is enforced on hardware we control.

  • Tenant resolution — inbound SIP headers and source IP are matched against the tenant registry, binding the call to one workspace and its script, voice clone and LLM temperament.
  • Admission control — unknown IPs are refused immediately with a 403-equivalent signalling error. Nothing unauthenticated gets as far as audio processing.
  • Media handling — RTPengine relays the audio and hands raw 16 kHz linear PCM to the session core over native sockets, exactly as the SoW mandates (no browser-emulation layer anywhere).
  • Encryption — TLS for signalling and SRTP for media wherever the client's side supports it; the direct-AudioSocket alternative could not offer this.
This is the specialist layer ◇ Kamailio/FreeSWITCH, RTP, jitter and codec behaviour are telephony engineering, not web engineering — the single reason the plan carries a dedicated VoIP hire rather than spreading the work across the existing team.
16 kHz PCM
2+
Session core · triage
Python 3.11 async · Redis
  • per-tenant concurrency quotas
  • VAD · AMD · IVR-DTMF — ~1.5s
  • qualification gate vs schema

The heart of what we build and own. Every accepted call becomes a lightweight non-blocking async task here, and three distinct jobs happen in sequence.

1 · AdmitQuota enforcement. Per-tenant channel ceilings (SoW example: 10 for Tenant A, 25 for Tenant B) plus a global cap, held in Redis so the count stays correct across processes and restarts.
2 · ClassifyTriage. Streaming VAD alongside live transcription produces a verdict within ~1.5 seconds: live human, answering machine, business IVR, or dead air. Machines get a voicemail drop; IVRs get DTMF navigation; silence gets a check-in then a drop.
3 · ScoreQualification gating. Conversation checkpoints tracked against a structured schema array, compliance flags evaluated in real time to drive branching toward transfer or disposal.
  • Session reset — on completion the thread's state cache is purged so no text memory leaks into the next call, and the channel slot returns to the pool.
  • Stack — Python 3.11+ with FastAPI/asyncio, per the SoW's mandated runtime.
Who builds it ◇ Our two senior Python engineers plus one mid. This is demanding async work but it is squarely within the team's existing capability — the difficulty concentrates in AMD tuning, which the telephony hire owns jointly.
⏸ live human
only
+ ↓ drop
50–70%

Not a failure path — the business model. Most of what an outbound dialer connects to is not a person, and every one of those calls is filtered here, on infrastructure that costs us almost nothing to run.

  • Answering machines — intercept the greeting, wait for the tone, play the voicemail drop, hang up.
  • Business IVRs — navigated out-of-band with DTMF tones rather than conversation.
  • Dead air — a check-in hook fires, then a clean drop when nothing returns.
  • All three terminate before the engine leg is bridged, so they consume zero paid engine minutes.
The arithmetic ◇ At 50–70% of connects filtered, only ~45% of channel-minutes become paid engine-minutes. That is the difference between $105–185k/month and roughly double it at 500 channels — and why decision D2 (owning the edge) was not negotiable.
The risk ◇ AMD accuracy cuts both ways: false positives hang up on real prospects, false negatives burn engine spend. Measured from pilot day one, with a target agreed with the client.
3+
Engine adapter
first paid minute
  • STT → LLM → TTS, barge-in
  • locked prompt template injected

Only confirmed humans arrive here, and this is the first point at which we spend money per minute. The adapter is a thin interface of our own design; the provider sits behind it.

  • What the provider does — the streaming STT → LLM → TTS loop, barge-in when the human starts speaking, and the sub-second latency budget. Retell or Vapi, chosen by bake-off in phase 0.
  • What we do — inject the tenant's locked prompt template with its campaign variables resolved, hold the qualification schema, and own the call's lifecycle either side of the conversation.
  • Silence behaviour — a nudge at 2.5s, terminate if a further ~3s passes, per the SoW.
Why an adapter and not a direct integration ◇ It makes the engine a swappable dependency. A later move to a self-orchestrated pipeline (Deepgram + LLM + Cartesia/ElevenLabs) becomes a swap rather than a rewrite — worth $60–110k/month at 500 channels, reviewed at the phase-3 gate with real volumes in hand.
outcome
4+
Disposition
ViciDial APIs
  • qualified → warm transfer
  • else → tag NI / DNC
  • purge state, recycle channel

Where the platform delivers or destroys its value. A qualified conversation must become a human-to-human call, and an unqualified one must land correctly in the client's dialer.

QualifiedCall ViciDial's conference API to bridge the prospect into the human closer queue, then drop the bot leg out of the stream — the prospect is left talking to a person, mid-conversation.
Not qualifiedCall the external status API to tag the lead NI or DNC, then disconnect the audio loop. The disposition is what the client's reporting and compliance depend on.
ThenPurge the thread's state cache and return the channel to the pool, ready for the next dialer trigger.
  • The same integration layer later carries blind_monitor for the QA bot's live audio tap in phase 3.
Engineering read ◇ Moderate difficulty but quirky legacy APIs — well documented, inconsistently behaved. Owned by the mid-level Python engineer against a real ViciDial lab, never against documentation alone.
Alongsidecontrol · evidence · vendors
+
Support portal
Next.js · RBAC · audit

Amendment A's control plane: the surface through which support staff change campaigns without touching the system. Next.js front end against a FastAPI service that shares the core's data models.

  • Campaign requirements box — plain English in, variable injection out. Daily script rules, active promos and targeted offers propagate to active bots immediately.
  • Voice & accent dropdowns — swap voice clones, accents or synthetic engines (ElevenLabs, Cartesia) per tenant workspace.
  • RBAC — prompt internals, API webhooks and billing structures are invisible to non-admin accounts. Support staff can only reach the variables.
  • Audit log — append-only and hash-chained, capturing UTC timestamp, username, login email, origin IP, target campaign, variable changed and before/after values.
Sequencing ◇ The portal is phase 2, but the locked-template data model lands in phase 1 — variable injection has to exist before there is a screen to edit it. Built by the Next.js developer joining around week 6.
+
Live QA bot
phase 3 · ticket <60s

Amendment B, and a separate product surface: it monitors human agent calls for compliance, not our own bot calls. Delivered in phase 3.

  • Audio tap — ViciDial's blind_monitor Non-Agent API is our primary route because it needs only a basic API user, not Level 9 admin. SIPREC forking is offered to clients who actually run an SBC; a ghost-agent WebRTC listener is the fallback.
  • Stereo transcription — streaming STT with the agent channel separated from the customer channel.
  • Rule evaluation & scoring — an LLM checks the live transcript for mandatory compliance lines, buyer requirements and qualification markers, then scores whether age verification, medical-status checks and disclaimers were met or missed.
  • Ticket out — compliance metrics, verified script markers and the full transcript webhooked to the client CRM within 60 seconds of hangup.
Costing ◇ Meters on monitored human-agent hours, not bot calls — roughly $1.0–1.3 per monitored hour. Quote it to the client as its own metered line, since its volume driver is unrelated to bot traffic.
+
Platform & evidence
Postgres · Redis · S3 · K8s

The foundation, and a point of compliance with the SoW: every mandated technology is used as specified, with nothing substituted.

PostgreSQLPersistent multi-tenant profiles, configuration schemas, prompt templates and the immutable audit log.
RedisReal-time channel state, concurrency counters and lock management — the authority on how many channels a tenant currently holds.
S3Transcripts and recordings, compressed, with configurable per-tenant retention.
RuntimeUbuntu 24.04 LTS, fully containerised with Docker — Compose for the pilot, Kubernetes from GA for horizontal scaling and failover.
ObservabilityPer-call trace IDs, per-tenant dashboards, SLO alerting — the basis of running this as a managed service.
Owned by ◇ Our existing DevOps team at roughly 0.5 FTE — the workstream that removes an entire category of risk from this plan, because it is capability we already have in-house.
Vendors — bought
Retell / Vapi · ElevenLabs
Client-side We build & own Bought Terminal / vendor ①–④ call-path stages ⏸ the gate where engine cost begins
+ Click any box to see what happens at that stage
Why this shape ◇
In outbound BPO traffic 50–70% of connects are machines, IVRs or dead air. Triaging them on our own near-free infrastructure — before the engine leg is bridged — roughly halves the engine bill.

Technical architecture

Components, transports & data stores.

Client side
ViciDial / Asterisk
Any version — one route entry, no dialplan surgery
Outbound trunks
Carrier costs stay client-side
Human closer queues
Warm-transfer destination
SIP
TLS / SRTP
Our platform
SIP media edge
Kamailio/FreeSWITCH + RTPengine — tenant resolve, allowlist
Session corePython async
FastAPI/asyncio — session pool, triage, qualification gates
Engine adapter
One interface, swappable provider — the hybrid hedge
Support portal
Next.js + FastAPI — RBAC, campaign variables, audit views
QA bot service
Stereo STT + LLM compliance scoring
PostgreSQL · Redis · S3
Tenant config & audit · channel state & locks · transcripts
HTTPS
webhooks
External services
Retell / Vapibuy
STT→LLM→TTS orchestration, barge-in, latency
ElevenLabs / Cartesiabuy
Voice clones & accents, per tenant
ViciDial APIs
Conference transfer · status (NI/DNC) · blind_monitor
Client CRM webhooks
Compliance tickets within 60s of hangup
Mandated stack, fully respected: Ubuntu 24.04 · Docker (Compose → K8s) · Python 3.11+ async · PostgreSQL + Redis · raw-socket 16kHz PCM — no browser-emulation layers, exactly as the SoW requires.

Build vs buy

Buy the commodity. Build the product.

Buy

Where someone else's core business beats ours

  • STT / LLM / TTS orchestration — Retell or Vapi, behind our adapter. Sub-second voice loops are their entire business; rebuilding now is months of risk for zero pilot value.
  • Voice clones & accents — ElevenLabs / Cartesia, per the SoW. A per-tenant config choice exposed in the portal.
Fastest to pilot ~$0.08–0.14 / min

Build

The differentiation and the margin

  • SIP edge, tenant routing, quotas, triage, qualification gating, dispositions & warm transfer — this is the product. Nobody sells it as a unit.
  • Support portal, RBAC, immutable audit, QA bot, CRM webhooks — standard web/API engineering; our existing team's home turf.
Our IP Halves the engine bill
The hedge that keeps paying ◇ Launching on a managed engine behind our own adapter interface means a later switch to a self-orchestrated STT/LLM/TTS pipeline is a swap, not a rewrite. At 500 channels that swap is worth $60–110k/month — reviewed at the phase-3 gate with real volumes in hand.

Team plan · who builds it

Peak seven. One new face.

RoleWhoAllocationOwns
Tech lead / architectSenior Python · existingFull-timeArchitecture, engine adapter, code reviews, client technical interface
Backend engineerSenior Python #2 · existingFull-timeSession pool, Redis quota enforcement, qualification gating, call lifecycle
Integrations engineerMid Python · existingFull-timeViciDial APIs — dispositions, conference transfer, blind_monitor — webhooks; QA bot in phase 3
Telephony / VoIP engineerSenior VoIPnew hireFull-timeSIP media edge, AMD/IVR triage tuning, SIP bridging, SIPREC later
Portal engineerNext.js dev · existingFrom ~week 6Support portal, RBAC UI, campaign variable editor, audit views
DevOpsExisting team~0.5 FTE avgIaC, CI/CD, Compose→K8s, observability, load-test infrastructure
QA / SDETExisting QAFrom phase 1SIPp call simulator, regression suite, compliance scenarios
PM / EMExisting0.25–0.5Client, scope, hiring
Peak 7 · average ~6 · one new hire40–45 pmThen 1.5–2.5 FTE to operate it as a managed service after GA

The hire is the critical path

Start recruiting day one

  • If it runs past ~4 weeks, bridge with a freelance Asterisk/FreeSWITCH contractor — ViciDial specialists are a healthy niche market.
  • Decide at month 4 whether a second telephony-leaning engineer is needed for on-call depth. Not now.

Two honest caveats

Say these out loud before committing

  • Managed service means on-call. Three people must be able to answer a 2 a.m. “calls aren't transferring” page: telephony, a senior Python, DevOps.
  • The .NET developers stay off this project. The SoW mandates Python/Node; forcing .NET in adds a stack for no benefit.

Phased build plan

Pilot at month 3. GA at month 5.

Workstream
M1M2M3M4M5M6M7
Phase 0 · Prove it
ViciDial lab · Retell vs Vapi bake-off · spike
w1–3
Telephony hire — recruit → onboard
critical path
Phase 1 · Pilot build
SIP media edge + tenant resolve
w4–12
Session core, quotas & triage v1
w4–12
Engine adapter + prompt templates
w6–12
ViciDial: dispositions + warm transfer
w6–12
Pilot ramp — 25–50 channels
w10–12
Phase 2 · Multi-tenant GA
Tenant manager + onboarding
w13–18
Support portal · RBAC · variables
w13–20
Immutable audit log — hash-chained
w15–19
Load test 100 ch + failure drills
w17–20
Phase 3 · QA bot & scale
QA tap — blind_monitor + STT
w21–26
Compliance scoring + CRM ticket <60s
w23–28
Scale validation → 500 channels
w25–28
Continuous
DevOps — CI/CD, K8s, observability
w2–28
QA — SIPp harness + regression
w6–28
Client demos — end of each phase
w4–28
◆ Milestones
Pilot live25–50 ch · month 3
GA100 ch · month 5
Full SoWincl. QA bot · month 7
Prove Pilot build GA & portal QA bot & scale Continuous Hiring dependency
Honest ranges ◇ Pilot 3–4 months, full scope 6–8 months — the variables are the hire's start date, client staging access and ViciDial version. Phase 0 is deliberately cheap: if the spike fails we learn it in three weeks, not seven months.

Cost model · monthly run rate

Infrastructure is cheap. Minutes are not.

Cost linePilot · 50 chGA · 100 chScale · 500 ch
Compute — SIP edge + app core$300$600–800$2,200
PostgreSQL + Redis (multi-AZ from GA)$180$645$1,290
K8s, LB, NAT, S3, monitoring, backups$200$450$800–1,000
Staging + dev environments$300$350$400
Egress (audio ≈ 64 kbps/leg)$50$100$450
AWS subtotal on-demand$1.0–1.4k$2.1–2.5k$4.7–6k
Paid engine-minutes / month after triage filtering~155k~310k~1.5M
AI engine cost $0.08–0.14/min; negotiated at scale$12–22k$25–43k$105–185k
Volume basis
8 effective hrs/day × 22 days × ~65% utilisation ≈ 6,900 channel-minutes per channel/month. Triage filters 50–70%, so ~45% become paid engine-minutes.
QA bot metering
Driven by monitored human-agent hours, not bot calls. Stereo STT + LLM scoring ≈ $1.0–1.3 per monitored hour. Quote as its own metered line.
Build cost
40–45 person-months over 6–8 months. Monetary figure [placeholder] — apply internal blended rate + the telephony-hire salary line.
Pricing rule ◇ Engine minutes are a pass-through-with-margin line — never absorbed. At 500 channels the engine concurrency cap itself becomes an enterprise negotiation, so that contract must be signed before the 100→500 ramp. Rates verified July 2026; re-price at procurement.

Risk register · the ones that bite

What we watch, and how we cover it.

Delivery risk

Schedule and capability

  • Telephony hire slips past 4 weeks → recruit from day 1; contractor bridge ready.
  • Client ViciDial version quirks → our own SIP edge minimises client-side dependency; lab + staging in phase 0.
  • Voice-to-voice latency over ~1s → measured in the phase-0 spike, before commitment; region colocation.
  • On-call burnout on a small team → three trained responders, alert hygiene, 2nd hire reviewed at GA.

Commercial & compliance risk

Margin, trust and law

  • AMD accuracy below the business bar → wasted engine spend; measured from pilot day 1, target agreed with client.
  • Engine concurrency caps or price moves → enterprise agreement before scale; the adapter keeps alternatives credible.
  • Cross-tenant data leakage → tenant-scoped keys, isolation tests in CI, security review, pilot exit criterion.
  • TCPA/DNC, recording consent, medical data → client owns campaign compliance; we supply disposition mechanics, audit trail, retention controls.

Next steps

Six answers we need from the client.

The plan holds without these — but each one moves a number. Volumes move the engine bill most.

1 · Committed volumes
Tenants at go-live, concurrent channels, expected monthly minutes. Drives the engine bill and therefore our pricing.
2 · Acceptance criteria
Latency target, AMD accuracy threshold, uptime SLA. The SoW names none.
3 · Who signs the engine contract
Us or them — and therefore who carries per-minute pricing risk.
4 · Compliance jurisdiction
Recording-consent rules, and whether medical-status campaigns imply HIPAA-adjacent handling.
5 · QA monitored volume
Monitored human-agent hours per month — the QA bot's metered cost scales with it.
6 · Data retention
Policy for transcripts, recordings and audit logs, per tenant.
Recommended first move ◇ Approve phase 0 only — three weeks, a ViciDial lab, an engine bake-off and one end-to-end spike call. It converts every remaining estimate on these slides into a measured number before the bulk of the budget is committed.
1 / 12