Textify Voice: Product & Functional Specification

Status: draft for implementation · Owner: Joshua Saimon Sakweli (QBIT SPARK) Companion doc: ARCHITECTURE.md (components, data model, APIs, infra). This file is 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: agencies and resellers ("partners") brand the platform as their own, set their own prices, and onboard their own customers. Customers top up a prepaid wallet with mobile money or card.

We are adding a third channel: a call center / business phone line product, similar in spirit to SemaCall (semacall.com): "One business. One number. Every team." Customers call one number; the call reaches the right person (or an AI answers) in the customer's language.

The voice capability is built as a separate service ("Voice Service") in Java Spring Boot. Textify consumes it as a client. The Voice Service must not know about Textify's users, auth or money.

2. Goals

  1. A Textify customer can get a Tanzanian phone number and have every incoming call answered, by an AI receptionist (Swahili first, English supported) or by human agents in the browser.
  2. AI can hand the caller over to a human when needed.
  3. Every call is logged, optionally recorded, transcribed and summarized.
  4. Missed calls trigger an automatic SMS/WhatsApp follow-up (Textify already does messaging).
  5. Usage is billed per minute from the existing Textify wallet.
  6. The Voice Service is reusable by other QBIT SPARK products later (JikoXpress, Mauzodukani, NexGate) without changes.

3. Non-goals (for now)

4. Key terms (plain language)

Term Meaning
PSTN / telco network The normal phone network (Vodacom, Airtel, Yas, Halotel, TTCL).
SIP The protocol internet phones use to set up calls (ring, answer, hang up). Like HTTP but for calls. Voice audio travels separately over RTP.
SIP account One login for one phone/softphone (like an email account but for calls).
SIP trunk A connection carrying many calls at once between two systems over SIP. Here: Africa's Talking ⇄ our LiveKit.
Human agent A staff member who answers calls (in the browser app).
AI agent A bot that talks on the phone: listens → thinks → speaks.
STT / LLM / TTS Speech-to-text, the language model (the "brain"), and text-to-speech (the voice).
Realtime / speech-to-speech model One model that hears and speaks directly (e.g. OpenAI Realtime).
LiveKit room A live audio session. Each phone call = one room. The caller joins as a "SIP participant"; AI or humans join the same room.
Dispatch rule LiveKit config that decides which room an incoming call goes to and which AI agent joins.
DTMF Keypad presses during a call ("press 1").
Cold / warm transfer Cold: just forward the call. Warm: AI briefs the human first, then hands over.

5. Providers we use and why

Provider Role Why
Africa's Talking (AT) Tanzanian phone numbers + connection to all TZ telcos + SIP trunk Local numbers and licensing. LiveKit's own phone numbers are US-only.
LiveKit (self-hosted, open source) Media server: rooms, SIP, browser audio, recording, transfers Already used in production by us for NexGate (video, spaces, audio calls). Self-hosted = no per-minute LiveKit fee.
OpenAI AI brain + voice (Realtime model), transcription, summaries Best overall quality. Swahili quality must be tested; TTS can be swapped.

6. Costs (Africa's Talking Tanzania, as published on 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 as regular, plus TZS 170,000 deposit
Regular incoming TZS 17 / min
Regular outgoing TZS 60 / min
Toll-free incoming TZS 200 / min
SIP agent leg TZS 4.30 / min
SIP trunk TZS 8.61 / min
Conference TZS 8.61 / min
TTS (Google, via AT) per character

6.1 How the costs combine

Every call has leg 1 (customer ⇄ our AT number) and, if someone answers, leg 2 (our number ⇄ whoever answers).

Customer ──leg 1──> AT number ──leg 2──> answerer
          17 in / 60 out          SIP trunk to LiveKit: 8.61
                                  forward to a mobile: 60   (avoid)
Scenario Approx. cost per minute
Inbound call into LiveKit (AI or browser agent) 17 + 8.61 ≈ TZS 25.61 + AI cost if AI answers
Outbound call from LiveKit to a customer 60 + 8.61 ≈ TZS 68.61 (to confirm)
Inbound forwarded to a staff mobile (fallback only) 17 + 60 ≈ TZS 77

Key facts already agreed:

6.2 AI cost (on top of telco)

An AI-answered minute adds OpenAI cost (Realtime, or STT + LLM + TTS). This is several times the telco cost per minute. Exact per-minute figures must be measured during the PoC from real calls (token/audio usage logged per call).

6.3 Indicative selling prices (suggestion, to be finalized after PoC)

Item Suggested price
Number rental TZS 60–75k / month
Inbound minute, human-answered TZS 40–50 / min
Outbound minute TZS 90–100 / min
AI-answered minute TZS 150–250 / min
AI summary add-on + TZS X / min (set after measuring)

Pricing lives in Textify only. The Voice Service only reports usage.

7. Users & personas

8. Functional requirements

8.1 Numbers

8.2 Inbound calls

8.3 AI receptionist

8.4 Human agents (browser)

8.5 Recording, transcription, summary

8.6 Missed calls & follow-ups

8.7 Usage & billing

8.8 Dashboard (built in Textify, data from the Voice Service)

9. Non-functional requirements

Area Requirement
Latency AI response start < ~1 s after the caller stops speaking (target). Call connect < 3 s.
Availability Voice Service must keep taking calls if Textify is down (fail-open balance check, queued webhooks).
Isolation Dedicated LiveKit box for Textify Voice. Not shared with NexGate.
Security SIP/RTP ports open only to Africa's Talking IPs. Service tokens between apps. Signed webhooks. No user PII beyond phone numbers.
Privacy Consent notice, retention policy, recordings in our storage, access only via the client app.
Language Swahili first-class. Test quality with real Tanzanian callers before selling AI.
Simplicity No approval workflows, no internal OAuth, minimal moving parts.

10. Phases

Phase 0: Proof of concept (goal: one real call end-to-end)

  1. Confirm with AT (see §11). Get one TZ number + SIP trunk.
  2. Dedicated box: LiveKit server + LiveKit SIP + Redis. Firewall restricted to AT.
  3. Inbound trunk + dispatch rule → Spring Boot dials OpenAI Realtime into the room over SIP → AI greets in Swahili.
  4. Measure: latency, audio quality, OpenAI cost per minute.
  5. Swahili test: 10–20 real people (Swahili, English, mixed). Judge understanding and voice. Swap TTS if the voice is weak.

Phase 1: MVP (sellable)

Phase 2

Phase 3

11. Open questions for Africa's Talking (must answer before Phase 1)

  1. Can the TZ SIP trunk route inbound calls for our number to an external SIP URI (our LiveKit SIP endpoint)? Note: LiveKit SIP does not support SIP REGISTER, so AT must send calls to us directly.
  2. Can it accept outbound calls from our server IP (and what auth: IP allowlist or username/password)?
  3. What are AT's SIP signalling and media IP addresses (for our firewall allowlist)?
  4. Exact billing for inbound to trunk: 17 + 8.61? Any extra?
  5. Exact billing for outbound via trunk: 60 + 8.61? Any extra?
  6. Is the SIP agent TZS 4.30 charged on inbound calls too? Any setup/monthly fee for SIP agents?
  7. Are unanswered rings to SIP endpoints billed? 7b. The listed regular number is Airtel. How do callers on Vodacom, Yas, Halotel and TTCL reach it, and at what cost to them and to us?
  8. Calls-per-second (CPS) limits and pricing in Tanzania (needed for broadcast).
  9. Supported codecs (G.711 PCMU/PCMA expected) and DTMF method (RFC 2833/4733).
  10. Does reselling voice to our customers need any TCRA licence on our side, or is AT's licence enough? Get it in writing.
  11. Number porting / getting several numbers quickly; toll-free availability.

AT is not on LiveKit's list of tested SIP providers (Twilio, Telnyx, Exotel, Plivo, Wavix, Sinch, didlogic). LiveKit is designed to work with any SIP provider, so the PoC must prove compatibility.

12. Risks

Risk Mitigation
AT trunk can't deliver to an external SIP URI Verify first (§11 Q1). Fallback: AT Voice XML + AT SIP agents for humans; AI limited.
Swahili STT/TTS quality poor Early real-user test; swap TTS provider; keep human fallback prominent.
AI cost higher than expected Measure in PoC; short answers; pre-recorded greetings; cheap model for simple turns; price AI minutes higher.
SIP fraud/attacks Firewall to AT IPs only; LiveKit inbound trunk allowed_addresses + numbers.
Textify outage blocks calls Fail-open balance check; queued + retried webhooks.
Regulatory (TCRA, PDPA) Written confirmation from AT; consent notice; retention policy.
Single box failure Phase 1 single box is OK; add a second node (LiveKit supports multi-node via Redis) when volume grows.

13. Decisions log

# Decision
D1 Numbers and telco via Africa's Talking; media via self-hosted LiveKit; AI via OpenAI.
D2 All calls go through the SIP trunk into LiveKit (no split IVR on AT XML), for one call path.
D3 Agents answer in the browser (no forwarding to mobiles by default).
D4 Dedicated LiveKit box for Textify Voice, separate from NexGate's LiveKit.
D5 Separate Voice Service in Java Spring Boot. Knows no users/auth/money; owns numbers, routing, calls, recordings, usage events.
D6 Textify (Go) owns users, tenants, partners, wallet, pricing, dashboard, messaging follow-ups.
D7 Preferred: no Python. OpenAI Realtime joins the LiveKit room as a SIP participant, controlled from Spring Boot via OpenAI's call-control REST + WebSocket (ARCHITECTURE §2.5). Fallback: thin Python LiveKit Agents worker (§2.2) if OpenAI SIP interop or Swahili voice quality fails the PoC.
D8 Billing is per minute from the Textify wallet; Voice Service emits usage events only.
D9 Recording default on with consent notice; 90-day retention default.
D10 No approval workflows anywhere.

Revision #1
Created 21 October 2026 13:05:36 by Admin Qbit
Updated 21 October 2026 13:06:07 by Admin Qbit