ConsentIVR - Documentation
Consent-first voice, SMS, and WhatsApp communications - enforced in code.
01Overview
ConsentIVR is a Flask-based inbound IVR and opt-in outbound communications platform. An inbound IVR routes callers through editable menus; outbound campaigns place appointment reminders and surveys over voice, SMS, or WhatsApp. Operators run and monitor everything from a web dashboard or an interactive Telegram console, with optional live alerts.
Menus, business hours, campaigns, and recipients live in the database - routing and campaign settings can be changed without editing application code.
At a glance
| Metric | Value |
|---|---|
| Channels | 3 - voice, SMS, WhatsApp |
| Pluggable providers | 5 |
| Consent gates per contact | 3 |
| Operator-console languages | 5 |
| Identity secrets captured | 0 |
Key design goals
Data-driven routing
Menus and keypad options are rows in ivr_menus / ivr_options, edited from the dashboard. A global inbound mode can send every call to the menu, a forwarding number, voicemail, or a closed message.
Consent is the gate, not a note
Outbound dialing lists are built only from granted consent records, and three gates are re-checked for every recipient at send time - the import check is never trusted on its own.
02Architecture
Signed carrier webhooks in, a thin Flask core, short-lived SQLite connections. Each layer is a handful of small modules, and one command runs the web app, the webhooks, and the Telegram bot together.
| Layer | Modules |
|---|---|
| Carriers | Twilio · Telnyx · Plivo · Vonage · console |
| Providers | providers.py - send_message(), place_call() |
| Web / TwiML | ivr · outbound_voice · sms · webhooks · dashboard |
| Telegram bot | api (long-poll) · middleware · handlers · keyboards · i18n · access · payments |
| Core logic | consent · hours · jobs + joblock · validate · crypto |
| Storage | SQLite / SQLCipher (WAL) - contacts · consent · opt_outs · campaigns |
Startup
python app.py
This single command serves the web app, the carrier webhooks, and the Telegram bot in one process.
03Inbound call flow
Every Twilio/Telnyx webhook is verified by signature before any of the following runs.
-
Call arrives → check inbound mode
ivr forward voicemail closed
-
Business hours check (mode
ivronly)open → entry menu closed → after-hours + voicemail -
Menu - gather one digit
dial submenu voicemail message optout repeat
-
Warm transfer on
dialThe agent hears a whisper before bridging; the caller can press*to leave. Unanswered calls fall through to voicemail. -
Post-call menu
After the agent call ends, the caller can return to the menu instead of being dropped.
04Outbound campaigns
Appointment reminders and surveys are paced one recipient at a time. Every send passes three gates, re-checked at dial time.
Suppression / DNC list, matched on canonical E.164 so (415) 555-0123 and +14155550123 are the same person.
Granted for this purpose and this channel. SMS and WhatsApp consent are distinct from voice.
Calling-window check. Outbound fails closed: no window configured means nothing is dialed.
voice · SMS · WhatsApp
Supporting mechanics
Background runner
Launches run in a thread so the dashboard returns at once; a SQLite single-flight lock stops two workers dialing the same campaign.
Press 0 for an agent
Reminder recipients can be warm-transferred to a live agent mid-call, with a whisper and a no-answer fallback.
STOP / START
An inbound STOP writes an opt-out instantly; START re-subscribes. Honored across SMS and WhatsApp.
05Capabilities
Each capability is a small, self-contained module.
| Capability | Description |
|---|---|
| Surveys & results | DTMF answers with optional labels (1=Poor…), a per-question breakdown with bars, and label-aware or raw CSV export. |
| Phone validator | Offline libphonenumber - validity, line type, region, carrier, timezones - cross-checked against your own opt-out and consent records. |
| Voices & AMD | Per-campaign and per-menu Amazon Polly voices; per-campaign answering-machine detection. |
| Messages log | Every outbound text and inbound reply, with delivery status and a direction filter. |
| PGP exports | Result CSVs with PII download as .csv.pgp to a configured public key - or the export aborts rather than leak plaintext. |
| At-rest encryption | Set a key and the whole database opens with SQLCipher; if the driver is missing, the app refuses to start unencrypted. |
06Telegram operator console
A second control surface beside the dashboard: an interactive bot that mirrors the same operations and reuses the same consent gates, so the two can never drift.
Module layout
| Path | Modules |
|---|---|
| tgbot/ | api (long-poll, requests) · middleware (auth · rate-limit · locale) · handlers · keyboards · i18n · access · payments |
Features
Full operator parity
Live stats, launch / pause campaigns, add consent-checked recipients, manage opt-outs, flip inbound mode, and validate numbers - all from inline keyboards.
Allowlist + roles
Access is per Telegram ID, never open. Bootstrap admins from env; roles mirror the dashboard - viewer reads, operator changes state, admin manages operators. Every action is audited.
Localized
Five languages - English, Spanish, French, Portuguese, German - chosen in-chat, each with its own slash-command menu.
Optional paid access
A user who isn't on the allowlist sees their own ID to request access, plus buy-access buttons - Telegram Stars or Crypto Pay - and a Learn-more link. A completed payment grants a console role for a configurable window, recorded in tg_payments for accountability.
Same safety model
Phone numbers in bot views are masked like the alerts; there is no identity-secret surface; and paid access only ever grants an operator-console role - never the consent, opt-out, or calling-time gates.
07Provider matrix
One interface, selected per channel by env var. Voice reuses the same TwiML - Telnyx reads it as TeXML. console logs instead of sending, for free local testing.
| Provider | SMS | Voice | Notes | |
|---|---|---|---|---|
| twilio | Yes | Yes - TwiML | Yes | Default backend. |
| telnyx | Yes | Yes - TeXML | - | Voice via a TeXML application. |
| plivo | Yes | - | - | SMS only here. |
| vonage | Yes | - | - | SMS only here. |
| console | Yes | Yes | Yes | Logs - no account, no charges. |
08Design principles
Enforced in code, not just documented.
No prompt, route, or column for OTPs, SSNs, card numbers, or passcodes. The only digit the IVR reads is a menu selection.
Prompts speak your real organization name; caller ID is a number you own. No spoofing configuration exists.
Dialing lists come only from granted consent, re-checked per recipient at send time.
Checked before every outbound call or text; callers opt out by keypress or STOP.
When enabled, the disclosure plays before any audio is captured.
Every carrier webhook is signature-verified; the Telegram console is an explicit per-user allowlist with roles.
09Out of scope
10Compliance responsibilities
The system provides the controls; compliance is how you operate it. Still your responsibility:
- The telemarketing, calling-time, recording-consent, and privacy laws that apply to you.
- TCPA, state two-party-consent recording rules, and local equivalents.
- Obtaining appropriate legal guidance for your specific use case.