Skip to main content

Textify Voice: Product & Functional Specification

Status: draft for implementation · Owner: Joshua Saimon Sakweli (QBIT SPARK) · Updated 2026-11-08 Companion:Companion docs: FLOWS.md (flow & action reference) · ARCHITECTURE.md (components, flows, data model, APIs, infra). Written so a new engineer, or a new AI coding session, can pick up the work with no prior context.


1. Background

Textify Africa (textify.africa) is an existing bulk SMS + WhatsApp platform, written in Go, live in Tanzania, Uganda and Nigeria. Its main model is white-label: partners brand it as their own and onboard their own customers, who top up a prepaid wallet.

We're adding voice / call centerVoice as a new Textify module, so the same Textify customers can use it from the same portal and wallet. TheIt productcombines:

is
  • a call center (one business number, menus, browser agents), similar in spirit to SemaCall (semacall.com: "One business. One number. Every team")com), plusand
  • Textify's own strength, bulk: voice broadcast campaigns with keypad actions and SMS fallback.

Voice isruns built ason a separate service, the Voice Engine (Java Spring Boot). It is an engine: itblind knows nothing aboutto users, logins, roles orand money. It is told what to do with numbers and calls and reports what happened. Textify consumes it like any other API. Other QBIT SPARK products (JikoXpress, Mauzodukani, NexGate) can consume it later.

Status: we already have a working Tanzanian number from Africa's Talking.

2. Goals

  1. ACustomers Textify customer getsget a numbernumber, withchoose ahow it answers (Direct, greetingMenu, +later keypad menuAI), and calls reach human agents answering in the browser.
  2. Outbound:Callers agentswaiting makefor an agent hear click-hold music, never silence; nobody waits forever (voicemail).
  3. Click-to-call callsoutbound fromfor the browser.agents.
  4. Broadcast campaigns: send a recorded voice message to thousandsthousands, ofkeypad numbers,actions with "press 1 to (talk to us"us, confirm via webhook, opt out…), retries, opt-out, and SMS fallback for peoplenon-answerers.
  5. who
  6. Customers didn'tcreate answerwhat callers hear by uploading/recording audio or typing text (Basic or Premium voice).
  7. Keypresses can trigger the customer's own systems (webhooks with parameters).
  8. Every call is logged, optionally recorded, and (Phase 2) transcribed + summarized by AI.
  9. Missed calls / voicemails →become automaticfollow-ups in Textify (tickets, SMS/WhatsApp from Textify.WhatsApp).
  10. BillingPredictable percosts: per-minute /call per answered callbilling from the existing Textify wallet.wallet; voice-generation cost known before it's spent.
  11. (Phase 3) AI receptionist andwith AIa outboundper-business callsknowledge onbase, thehanding sameover engine.to humans.

3. Non-goals

  • NoEngine has no users, auth,auth of people, roles, plansplans, prices, money, tickets or prices in the engine.contacts.
  • No approval workflows anywhere.
  • Everything
  • No self-service.live text-to-speech during calls (no AT <Say>; all text becomes audio files first).
  • No video over phone lines.
  • No message broker (Kafka/RabbitMQ/MQTT) in v1v1. (seeNo ARCHITECTURE §7).Python.
  • Countries other than Tanzania (later, same design).

4. Key terms (plain language)

ofnumbers.
Term Meaning
PSTN Normal phone network (Vodacom, Airtel, Yas, Halotel, TTCL).
AT Africa's Talking: our numbersnumbers, andPSTN connectionboth todirections, allvoice TZ networks.callbacks/XML
Voice callback / XML AT POSTs to our URL when something happens on a call;URL; we reply with XML instructionsactions (Say,Play, Play,GetDigits, GetDigits,Dial, Dial, Record…Record…).
SIPProtocol internet phones use to set up calls. Audio travels separately (RTP).
SIP / SIP trunk ConnectionInternet carryingcall manyprotocol calls/ betweenthe two systems. Here: AT → ourLiveKit LiveKit.connection carrying calls
LiveKit room A liveLive audio session.session; Eacheach answeredconnected call = one room;room the (caller and+ agents (andagent, later AI) are participants.
Browser agent Staff answering calls in the Textify web app
DepartmentA group of agents that calls ring (LiveKita JSring SDK).group)
Flow WhatGraph of nodes deciding what happens whenon a numbercall rings: greeting → menu → route. Stored as JSON.(FLOWS.md)
EndpointNode / actionOne step: play, menu, collect, connect, voicemail, webhook, branch, sms, optout, hangup, ai
Message Something thatcallers canhear: takeuploaded aaudio, call:or ringtext groupturned ofinto agents, voicemail, AIaudio (later).Basic/Premium voice)
Campaign A broadcast: onea audioflow messagerun tofor every answered call on a recipient list
EndpointA customer's saved webhook URL + secret, used by webhook actions
Knowledge base (KB)Business facts the AI uses (Phase 3)
DTMF Keypad presses ("press 1").

5. Product structure (what customers see in Textify)

Voice
├── Numbers          get/assign numbers
├── Call Center      inbound + agents
│   ├── Answer mode: Direct | Menu | AI (Ph 3)
│   ├── Departments & agents
│   ├── Business hours, closed message
│   ├── Waiting: hold music, comfort message, max wait → voicemail
│   ├── Recording on/off
│   └── Click-to-call (agents calling one customer)
├── Campaigns        bulk outbound
│   ├── Message (audio or text, variables)
│   ├── Keypad actions (talk to dept, webhook, sms, opt-out…)
│   ├── Contacts, schedule, calling hours, retries
│   └── Results + SMS fallback to non-answerers
├── Audio library    uploads, recordings, generated voices
├── Integrations     webhook endpoints
├── Knowledge base   (Ph 3, for AI)
└── Calls & Tickets  call log, recordings, summaries; follow-up tickets (Textify-only feature)

Answer-mode templates generate flows; customers never see raw nodes (an advanced flow editor may come later; the format already supports it).

Answer modeCaller experienceAT actions
DirectGreeting → ring department → wait with music → voicemailPlay → (wait loop) → Dial → Record
MenuGreeting → "press 1 sales, 2 support" → that department → voicemailPlay + GetDigits → wait loop → Dial → Record
AI (Ph 3)AI answers from the knowledge base, hands over to a departmentDial → LiveKit + OpenAI → agents

6. Providers

forNexGate;Voice
Provider Role
Africa's Talking Numbers, PSTN bothin/out, directions,callbacks voice+ callbacks/XML, outbound call API, call recording, SIP trunk to LiveKit
LiveKit (self-hosted, dedicated box) Rooms +Rooms, browser agents (WebRTC), agent-hold audio, (PhasePh 3)3 AI participant. WeSeparate alreadyfrom runNexGate's LiveKit
TTS: getsBasicLight open-source model self-hosted on CPU (candidate: Piper Swahili voice), itsonly ownif boxquality and commercial licence pass the listening test
TTS: PremiumOpenAI TTS or Azure Speech (Swahili neural voices), chosen by listening test
OpenAI PhasePh 2:2 transcription + summariessummaries; (REST).Ph Phase 3:3 live AI voice (Realtime over SIP, controlled from Java)
MinIO (or Linode Object Storage)Audio library + recordings

6.7. Costs (AT Tanzania, africastalking.com/pricing, Oct 2026)

Item Price
Regular number (Airtel) Setup TZS 100,000 + 18% VAT; TZS 35,000/month + 18% VAT
Toll-free number Same + TZS 170,000 deposit
Incoming / Outgoing TZS 17 / min
OutgoingTZS 60 /per min
Toll-free incoming TZS 200 / min
SIP trunk TZS 8.61 / min
SIP agentTZS 4.30 / min (not used in our design)

How our calls combine:

Call type Approx. TZS / min
Inbound, onlymenu greeting/menu// waiting / voicemail (nostays agent)on AT) 17
Inbound answeredtalking byto browser agent (via LiveKit) 17 + 8.61 ≈ 25.61
Click-to-call outbound (agent in browser) 60 + 8.61 ≈ 68.61
Broadcast,Broadcast message only 60 per answered minute (unanswered likely free, confirm)
Broadcast, caller presses 1Broadcast → talk to agent 60 + 8.61 for thewhile talking part

AgreedVoice facts:generation (TTS): Basic = fixed server cost; Premium ≈ $15–16 per 1M characters (check current), always calculated before spending (at save or campaign creation). No AT <Say> usage. Waiting happens on AT (no trunk cost while waiting).

    Agreed:

  • Costcost follows minutes, not the number of agents.agents Unlimited(unlimited agentsagents); perno account.
  • Nomobile forwarding to mobiles by default (17 + 60 = 77/min).
  • AI (Phase 3) adds OpenAI cost per minute. Measure in the PoC before pricing.

Indicative selling prices (finalize after PoC): number TZS 60–75k/month; inbound answered 40–50/min; outbound 90–100/min; broadcast 100–150 per answered call; premium voice per message/character; AI minute 150–250; summary add-on TBD.250. Prices live in Textify only.Textify.

7. Personas

  • Business admin (Textify customer): number setup, greeting, menu, agents, ring groups, campaigns, call logs, recordings.
  • Agent: logs into Textify, sets Available, answers in the browser, click-to-call.
  • Caller / call recipient: anyone on any TZ network.
  • Partner (later): resells voice under their own brand.

8. Functional requirements

8.1 Numbers & flowsanswer modes

  • FR-N1: Ops registers AT numbers in the engine; Textify assigns a number to an account.
  • FR-N2: Each number has onean open-hours flow and a closed-hours flow (JSON,generated built in Textify's UI, stored and executed byfrom the engine)answer mode; FLOWS.md).
  • FR-N3: FlowBusiness nodehours typesper number (keeptimezone small)Africa/Dar_es_Salaam), with holidays list (optional).
  • FR-N4: Changes take effect on the next call; every save is a new flow version.
  • FR-N5: Test call: say,engine calls the customer's own phone and runs the flow.

8.2 Flows & actions (full reference: FLOWS.md)

  • FR-F1: One action system for inbound, campaigns and (Ph 3) AI.
  • FR-F2: Node types: play, menu (GetDigits with options), ringcollect, (ring group)connect, voicemail, webhook, branch, sms, optout, hangup., Phase(Ph 3:3) ai.
  • FR-N4:F3: FlowVariables: options:system, business hourscontact (open/closed branch)campaigns), recordingcollected, on/off,webhook ring timeout, no-answer action.result.
  • FR-N5:F4: SavingValidation aon save (no dangling outcomes, size limits, loop guard, variables exist, media ready, targets belong to account). No approvals.
  • FR-F5: Running campaigns are pinned to their flow takesversion.
  • effect
  • FR-F6: onNever fail the nextcaller: call.any Noerror approval.→ stored system message + graceful hangup.

8.23 InboundMessages & voice (what callers hear)

  • FR-M1: Every message is either uploaded/recorded audio or text.
  • FR-M2: Audio: mp3/wav/m4a/ogg, ≤ 10 MB, ≤ 5 min, or record in the browser → engine converts to phone-friendly MP3.
  • FR-M3: Text: language (sw/en), voice, tier Basic or Premium; max 500 characters per message.
  • FR-M4: Text becomes an audio file when saved (flows) or before dialing (campaigns, incl. per-recipient personalized text). No TTS during live calls.
  • FR-M5: Generated audio is cached by text + language + voice + tier; identical text is generated once.
  • FR-M6: Swahili number/currency/date normalization before TTS ("TZS 25,000" → "shilingi elfu ishirini na tano").
  • FR-M7: Premium cost shown before saving/starting; reported in usage (ttsCharacters, tier).
  • FR-M8: Generation failure: flow save shows an error and the previous version stays live; campaign stays unstarted or pauses (TTS_FAILED). Safety net at call time: a stored system file.
  • FR-M9: Listen/preview in the browser for audio and generated text.

8.4 Inbound, waiting and agents

  • FR-I1: AT callback → engine looks up number → account → flow.flow (open/closed by hours).
  • FR-I2: Balance check: enginewith asks Textify "can this account take a call?". TextifyTextify; unreachable → allow (fail-open).
  • FR-I3: No balance → shortsystem message, hang up.
  • FR-I4:I3: Recording notice when recording is on ("Simu hii inaweza kurekodiwa kwa ajili ya ubora wa huduma"; in English: "This call may be recorded for quality of service").
  • FR-I5:I4: Greetingconnect andto menua rundepartment → engine rings available agents in their browsers → caller waits on AT XMLwith (nohold LiveKitmusic cost).
  • →
  • FR-I6:agent ring nodeaccepts → call is dialed into LiveKit → caller hears hold audio → engine rings the group's available agents in their browsers.connected.
  • FR-I7:I5: Waiting v1: if all agents are busy, the caller stays on hold and the engine rings again as agents become freemusic (engine-sidesystem queue)default or customer upload), untiloptional thecomfort timeout.
  • message,
  • FR-I8:max Timeoutwait → noAnswer action:(usually voicemail,voicemail), hangup,optional keys while waiting (Phasee.g. 3)1 AI.= voicemail).
  • FR-I9:I6: NotEach handleddepartment byhas anyonea →waiting MISSEDorder →(oldest eventfirst). →When Textifyan sendsagent becomes available, the SMS/WhatsAppnext follow-up.waiting caller rings them.

8.3 Browser agents

  • FR-H1:I7: Agents are only an opaqueAgents: agentRef + display nameonly in the engine.engine; Textify owns the user.
  • FR-H2: Statusstatus AVAILABLE / BUSY / OFFLINE. Online; presence is automatic while the agent's browser is connected.
  • FR-H3: Ring popup + ringtone in the browser; first to accept wins; others' popups close.
  • FR-H4:I8: Ring strategy per group:department: ALL_AT_ONCE (default) or ROUND_ROBIN; first to accept wins.
  • FR-H5:I9: Mute,In-call: hangmute, up,hold (with music), transfer to anotheragent/department, agenthang or group.up.
  • FR-H6:I10: OptionalRing transferpopup shows the caller number; Textify adds the contact name and open tickets (screen pop, Textify-side).
  • FR-I11 (later, designed): position announcements, estimated wait, callback request (virtual hold), whisper to anagent, externalwrap-up mobile (off by default; extra cost).time.

8.45 Outbound: click-to-call

  • FR-O1: Agent clicks a number in Textify → engine places the callcalls via AT from the account's number (caller→ IDagent = that number).
  • FR-O2: Agent is alreadywaits in the call room in→ the browser and hears ringing. Customercustomer answers → connected.
  • FR-O3:O2: Balance check before dialing.

8.56 Outbound:Campaigns broadcast campaigns(broadcast)

  • FR-C1: TextifyCampaign creates a campaign:= account, from-number, audioflow (uploadedmessage file+ URL)keypad or TTS text,actions), recipients list,(with variable columns), start time, calling window (default 08:00–20:00 EAT), calls/sec + max calls per second / concurrent, retry policyretries (default 2 retries,2, 30 min apart, for no-answer/busy).
  • FR-C2: OptionalPersonalized keypadmessages optionsgenerated afterbefore the message: 1 → talk to agentsdialing (ring group), 9 → opt out. (Phase 3: 1 → AI.)FR-M4).
  • FR-C3: Opt-out / do-not-call list per account,account, always checked before dialing.
  • FR-C4: PauseStart / pause / resume / cancelcancel; any time (Textify pauses automatically whenon thelow walletwallet; runsengine low).pauses on generation failure.
  • FR-C5: Per-recipient result:results: ANSWEREDstatus, (seconds, keypress),keys NO_ANSWER,pressed, BUSY,actions FAILED,triggered, OPTED_OUT.cost.
  • FR-C6: Progress events (batched) + completion event.events; Textify can SMSSMS/WhatsApp everyone who didn't answer (key selling point).answer.
  • FR-C7: Throughput limited by AT'sAT calls-per-secondCPS / concurrent-call limits for our accountconcurrency (confirm).; Textify shows ETA.

8.67 Webhook actions (customer integrations)

  • FR-W1: Customers save endpoints (HTTPS URL + secret) in Textify; stored in the engine per account.
  • FR-W2: webhook node sends parameters with variables ({caller}, contact columns, {key}, {input.x}, {callId}, {campaignId}…).
  • FR-W3: Async (default, Phase 1): queued, retried up to 24 h; caller hears a fixed confirmation immediately.
  • FR-W4: Sync (Phase 2): engine waits ≤ 3 s; the response can set variables ({result.x}) and a message to play (generated on demand, then cached).
  • FR-W5: Signed (HMAC), idempotency key per call + node, HTTPS only, private/internal IPs blocked, failures never break the call.

8.8 Recording, transcription,transcript, summary

  • FR-R1: Recording per number/campaign (default on for agent calls, with notice).
  • ;
  • FR-R2:recorded Engineby downloadsAT, every recordingcopied into our storage immediately.
  • FR-R3R2 (PhasePh 2): transcript (Swahili/English) + summary JSON:JSON 2–3 line (summary, intent, resolved, follow-ups, sentiment, topic.topic).
  • FR-R4:R3: Retention default 90 days (per-accountper setting)account). Tanzania Personal Data Protection Act applies.

8.79 AI receptionist + knowledge base (Phase 3)

  • FR-A1: Answer mode AI or ai node anywhere (e.g. menu option, campaign key, noAnswer).
  • FR-A2: Swahili first, English if the caller speaks it; short spoken answers; never invents prices/policies.
  • FR-A3: Knowledge base per account, edited in Textify, stored in the engine: business profile (name, about, location, hours), services & prices, FAQs, departments with descriptions (for routing), rules (never do / when to hand over), optional documents (PDF/text).
  • FR-A4: v1 of AI: KB placed directly into the AI's instructions (no vector DB). Large KBs: search_knowledge tool over Postgres full-text/pgvector.
  • FR-A5: Live data via the customer's endpoints as AI tools (same endpoints as webhook).
  • FR-A6: Handover to a department (warm transfer); no agent → take a message.
  • FR-A7: Improvement loop: summaries flag questions the AI couldn't answer; Textify suggests adding them to the FAQ.

8.10 Follow-ups & tickets (Textify-only)

  • Built in Textify from engine events: missed call → "call back" ticket; voicemail → ticket with recording; unresolved AI call / follow-ups from summaries → ticket; manual "create ticket" by agents.
  • Fields: phone (+ contact), subject, status OPEN/PENDING/CLOSED, assignee/department, notes, linked calls/recordings/SMS/WhatsApp, optional due date. Customer timeline per phone number. No SLAs/escalations in v1.
  • The engine has no ticket concept.

8.11 Usage & billing

  • FR-B1: OnPer call end the engine emits usage:call: direction, seconds per leg (pstnSeconds, trunkSeconds, aiSeconds), AT's reportedAT amount, recorded, summary.actions triggered.
  • FR-B2: Per generation: ttsCharacters, tier. Per campaign: totals.
  • FR-B3: Textify prices and deducts. Thededucts; engine never handles money.
  • FR-B3: Events are idempotent (event id),idempotent, signed, retried until 2xx.retried.

8.8 Dashboard (in Textify; data from the engine)

Call log, call detail (audio, transcript, summary), number + flow editor, agents and status, ring groups, campaigns (progress, results, "SMS non-answerers"), simple stats (answered/missed, by agent, campaign answer rate).

9. Non-functional

Area Requirement
Availability Calls workcontinue if Textify is down (fail-open balance check, queued events)
Isolation Dedicated Voice box,box (not shared with NexGate'NexGate)
LatencyAT callback response < 500 ms; agent ring < 3 s; connect after accept within one wait segment (~10–15 s LiveKitmax)
Security SIP open only tofrom AT; API keys + HMACHMAC; between services; signed/verified webhookswebhooks; everywhereSSRF protection (ARCHITECTURE §8)
LatencyCallback XML response < 500 ms; call reaches agent browser ring < 3 s
Privacy Recording notice, retention, our own storage, signed URLs
Predictable costNo runtime TTS; premium cost known in advance
Simplicity REST + webhooks + Postgres + Redis + LiveKit.LiveKit No+ MinIO; no broker, no OAuth, no approval flowsapprovals

10. Phases

Phase 0: Proof of concept (on the working AT number)

  1. Working AT number (done) → set callback URL to the engineCallback → SayPlay greetinga file works.
  2. GetDigits menu works; keys arrive.
  3. Wait loop: GetDigits wrapping Play hold segment, callback every segment.
  4. Dial sip:{callId}@<livekit-sip-host> from the XML → caller lands in LiveKit room call-{callId}.
  5. Browser→ browser test page joins the room → two-way audio withhears the caller.
  6. CheckFinal ATcallback finalfields callback: (duration, amount, recording URL.recordingUrl).
  7. Outbound: ATOutbound call API → answer → Dial into LiveKitLiveKit.
  8. →
  9. Voice browserlistening hearstest: thesame customer.Swahili sentences in Basic candidate (Piper), Premium candidates (OpenAI, Azure), and AT Say for reference, played on real phones to 5–10 Tanzanians.

Phase 1: Call center MVP Accounts,Numbers; numbers,answer flowsmodes Direct + Menu; flow engine with nodes play, menu, collect, connect, voicemail, webhook (say/play/menu/ring/voicemail/hangup)async), branch, sms, optout, hangup; messages (audio upload/record + text Basic tier); waiting v1; browser agentsagents, (lobby,departments, ring, accept), ring groups + waiting,hold/transfer; click-to-call,call; recording to our storage,storage; missed-callmissed/voicemail events,events; usage events,events; balance check.check; test call; endpoints.

Phase 2: Bulk + intelligence Broadcast campaignsCampaigns (throttle,all window,FR-C); retries,Premium opt-out,voice; press-1-to-agent,sync results,webhooks; SMS fallback via Textify), OpenAI transcriptiontranscripts + summaries,summaries; businessstats hours,per stats.node/campaign.

Phase 3: AI ai flownode node: OpenAI Realtime joins the LiveKit room over SIP, controlled from Java;/ AI →answer humanmode; knowledge base; AI tools via endpoints; handover; improvement loop; AI outbound campaigns (reminders, confirmations, surveys). Swahili quality test with real callers first.campaigns.

Later (already designed):: position announcements, estimated wait, callback request, whisper, wrap-up time, advanced flow editor, partner white-label voice, other countries, other QBIT products as engine clients.

11. Questions for Africa's Talking (before Phase 1)

  1. Can XML Dial target an external SIP URI with a custom user part (sip:{callId}@our-host)? Transport, port, codecs (G.711), DTMF method?
  2. AT'sAT SIP signalling + media IPs (for our firewall andfirewall, LiveKit allowlist).
  3. Billing for Dial-to-SIP: is it 17 (or 60 outbound) + 8.61 trunk? Anything else?
  4. Does Dial record="true" record aDial-to-SIP Diallegs? toFormat, SIP,how andlong what'sAT keeps the recording format and retention on AT's side?file?
  5. Calls-per-secondCPS and max concurrent calls (inboundin + outbound)out) for our account; can they be raised?
  6. Outbound billingbilled per second or per started minute? Are unanswered/Unanswered/busy calls free?
  7. Can the outboundOutbound call API takeAPI: multiple numbers per request? WhatReturned session ids?
  8. Callback source IPs; any signature on callbacks?
  9. GetDigits wrapping Play: keys interrupt playback? Max timeout? Any limit on how many callbacks per call (our wait loop)?
  10. Play: timeout for fetching the URL; does it returnstream while downloading; any caching/pre-upload of media?
  11. After a Dial ends unanswered, does AT continue to the next XML (sessioncallback ids)after Dial)?
  12. DoAirtel voice callbacks come from fixed IPs? Is there any callback signature?
  13. The regular number is Airtel:number: any issues for callers from Vodacom, Yas, Halotel, TTCL?
  14. TCRA: doeslicence for reselling voicevoice; need a licence on our side? Rulesrules for automated/marketing calls (consent, hours, caller ID)?. In writing.

12. Risks

Risk Mitigation
AT can't Dial to our SIP URI Phase 0 testPoC step 24 first.first; Fallback:fallback AT SIP numbers on softphones for agents
Wait loop limits (callbacks/timeouts)PoC step 3; fallback: wait inside LiveKit with ingress music (no LiveKit)keys while waiting)
Basic TTS not good enough / licence not commercialListening test; Basic = Premium at lower price, or audio upload only
AT throughput limits slowslows broadcasts Confirm Q5; engine throttles; showthrottle; ETA in Textify
Swahili AI quality (PhasePh 3) Real-caller test; AI only where it passes; human fallbackhandover always available
SIP attacks / webhook SSRF FirewallAT-only +firewall; LiveKitendpoint allowlistIP to AT IPs onlyblocking
Textify outage Fail-open balance check;open, outbox retries
Regulation (TCRA, PDPA) Written answers; notices; opt-out; retention
Single boxFine for Phase 1–2; LiveKit/engine can scale out with Redis later

13. Decisions log

oneimplementationeach
# Decision
D1 Engine model: separate Java Spring BootSeparate Voice Engine (Java 21, Spring Boot), blind to users/auth/money; Textify (Go) consumes it via REST + webhooks
D2 AT is the only PSTN path, both directions (inbound callbacks; outbound call API)
D3 Greetings/menus/Greeting/menu/collect/voicemail/broadcast audiowaiting run on AT XMLXML; anything live (nogoes Dial → LiveKit cost)
D4 AnyAll callagents thatanswer needsin a person (or AI) isthe dialedbrowser intovia LiveKit via Dial sip:{callId}@livekit
D5 All agents answer in the browser via LiveKit (no AT SIP softphones, no mobile forwarding by default)
D6Three adapters inside the engine:Adapters: Telephony (AT), Media (LiveKit), TTS (Basic/Premium), AI (OpenAI),: plain Java interfaces,interfaces
D6No Python; Ph 3 AI = OpenAI Realtime over SIP controlled from Java (Python worker only as fallback)
D7 No Python: AI later via OpenAI Realtime over SIP, controlled from Java. Python LiveKit worker only as fallback
D8Service auth: API keykeys perin, client app (in), HMAC-signedHMAC webhooks (out),out, secret URL + IP allowlist for AT callbacks,AT, built-in signatures for LiveKit/OpenAI
D9D8 Communication: REST + webhooks + Postgres outbox/job tablesjobs + Redis + LiveKit data messages.messages; Nono Kafka/RabbitMQ/MQTTbroker in v1
D9Engine owns media (MinIO, ffmpeg, signed play URLs); Textify references mediaId
D10 BillingMessages per= minuteaudio or text; text → audio file at save / perbefore answereddialing; callno fromAT the<Say>, Textifyno wallet;runtime engine reports usage onlyTTS
D11Voice tiers Basic (self-hosted light model) / Premium (OpenAI or Azure), decided by listening test
D12One flow/action system (11 node types) for inbound, campaigns and AI (FLOWS.md)
D13Customers pick answer-mode templates (Direct / Menu / AI), not a flowchart editor (later maybe)
D14Waiting happens on AT (hold loop), not in LiveKit; LiveKit audio only for agent hold
D15Webhook actions via saved endpoints; async in Ph 1, sync in Ph 2; called by the engine directly
D16Knowledge base lives in the engine per account; prompt-stuffing first, search tool when large
D17Tickets/contacts/screen-pop live in Textify only
D18 Dedicated Voice box, separate from NexGate's LiveKit
D12D19 No approval workflows