Collecting payments over the phone is one of the places where a voice AI demo can go wrong fast.
An assistant can explain a balance, answer account questions, and help a caller choose a payment plan. But the assistant should not ask the caller to say a card number out loud, and the app should not receive raw PAN, CVV, expiration date, billing ZIP, or DTMF digits through ordinary logs or transcripts.
This Telnyx code example shows the safer pattern: use AI for the conversation, then use Telnyx Pay over Voice for the sensitive payment step.
The canonical code example: https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-pci-protected-payment-collection-python
What This Example Builds
A Python Flask app that:
- Answers inbound billing calls with Telnyx Voice API
- Starts a Telnyx AI Assistant on the active call
- Verifies the caller by name and date of birth
- Explains the past-due balance after verification
- Negotiates a simple payment plan
- Exposes a
start_secure_paymentwebhook tool to the assistant - Starts Telnyx Pay over Voice for keypad card entry
- Handles payment progress and completion webhooks
- Shows sanitized payment status in a local dashboard
- Records a PCI-safe event marker without exposing card details
Why Pay over Voice Matters
The important design choice is separating the conversation from the payment collection step.
The assistant handles the part that benefits from natural language: identity verification, account explanation, payment-plan negotiation, and consent to begin a secure payment flow.
Once the caller agrees, the assistant calls a backend tool. The backend starts Telnyx Pay over Voice. From there, Telnyx guides the caller through an IVR flow and collects card details via keypad.
That means the app is not building a card collection IVR from scratch. It is not using generic DTMF gather for card digits. It is not letting the assistant hear card details. Pay over Voice is the PCI-focused boundary.
Architecture
caller dials
-> Telnyx Voice API application
-> Flask /webhooks/voice
-> call.initiated
-> answer call
-> ai_assistant_start
-> assistant verifies caller and negotiates plan
-> assistant calls start_secure_payment
-> app starts Telnyx Pay over Voice
-> caller enters card details by keypad
-> payment progress/completed webhooks
-> dashboard shows sanitized proof
How The Call Flow Works
When Telnyx sends call.initiated, the app answers the call. When the call is answered, the app starts the configured AI Assistant with ai_assistant_start.
The assistant begins by explaining what the line can do: account status, billing questions, payment plans, and secure keypad payment collection. It then asks for the caller's full name and date of birth before disclosing account details.
After verification, the assistant explains the balance and offers a plan. If the caller agrees to a payment plan and consents to secure card entry, the assistant calls the start_secure_payment webhook tool.
The Flask app then starts Pay over Voice on the active call. Pay over Voice prompts the caller for:
- card number
- expiration date
- billing ZIP code
- security code
Each value is entered by keypad. The app receives payment progress and completion events, but it does not log raw card data.
Run The Example
git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/ai-pci-protected-payment-collection-python
cp .env.example .env
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Expose the app:
ngrok http 5000
Update .env:
TELNYX_API_KEY=KEY...
PUBLIC_BASE_URL=https://<ngrok-id>.ngrok-free.app
PAY_CONNECTOR_NAME=pci-protected-payment-demo
TOOL_SECRET=<generate-a-random-secret>
Provision the assistant and Pay Connector:
python provision_assistant.py
Copy the printed TELNYX_ASSISTANT_ID into .env, then start the app:
python app.py
Configure your Voice API application webhook URL:
https://<ngrok-id>.ngrok-free.app/webhooks/voice
Assign a Telnyx number to the application and call it.
Test Payment Flow
Use the demo customer from data/customers.json:
name: Jordan Lee
date of birth: 1990-03-15
balance: $342.50
Suggested conversation:
assistant: can you first tell me your full name?
caller: jordan lee
assistant: can you tell me your date of birth?
caller: march fifteenth nineteen ninety
assistant: your account is 45 days past due...
caller: can i pay forty dollars a week?
assistant: i can set that up...
caller: yes
When Pay over Voice starts, enter a valid test card by keypad:
4111111111111111
0827
94111
123
Production Considerations
- Replace the mock processor with your actual payment processor endpoint
- Use a production Pay Connector only after payment processor validation
- Add webhook signature verification with
TELNYX_PUBLIC_KEY - Keep payment status logs sanitized
- Store only the payment token, charge ID, or high-level status your workflow needs
- Review PCI scope with your compliance team before production use
- Keep the assistant instruction explicit: never ask callers to speak card details
Resources
- Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/ai-pci-protected-payment-collection-python
- Pay over Voice: https://developers.telnyx.com/docs/voice/programmable-voice/pay
- Voice API commands: https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-commands-and-resources
- Start AI Assistant: https://developers.telnyx.com/api-reference/call-commands/start-ai-assistant
- AI Assistants: https://developers.telnyx.com/docs/inference/ai-assistants
- Telnyx Portal: https://portal.telnyx.com