| Field | Value |
|---|---|
| Date | 09 Jun 2026 |
| Status | ✅ Complete |
| GitHub Commits | d9b5f9f, 51f6093, 86ab17f, 106e123, 124e6dd |
Post-billing invoice fixes, two new admin tools, and a Twilio security incident that
required full credential rotation and a definitive rethink of the Twilio authentication
architecture.
The Pay Online button on invoice PDFs previously linked to the portal API endpoint, which
returned JSON and failed for customers who were not logged in. Fixed by generating a direct
Stripe checkout URL at PDF-creation time (same approach as the invoice email).
While regenerating PDFs, discovered the production .env had the Stripe publishable and secret
keys reversed (pk_ in the secret slot, sk_ in the publishable slot). Corrected.
Still outstanding: production is on TEST keys. Must switch to LIVE keys before sending real
customer invoices.
Added a database-level unique constraint on CustomerCLI.cli so the same phone number can never
be assigned to two customers, regardless of entry method (API, admin, direct DB). Previously
only the API view checked for duplicates.
Added a button on the Sync page that re-runs the destination classifier on all CDRs sitting on
the International (Catch-all) destination. Replaces the manual shell script from Session 16. See
the Billing Operations admin manual for full documentation.
The GitHub repository was briefly made public (~30–60 minutes) while evaluating GitHub
integration. The repo contained wiki_sync.py, which held a Wiki.js API key. Combined with very
heavy legitimate API usage that session (bulk historical CDR sync of 8 AU1 subaccounts back to
2024-01-01), Twilio's automated systems flagged suspicious activity and applied restrictions:
SIP trunking / voice was NOT restricted — customer calls were unaffected throughout.
Almost certainly a false positive triggered by the brief public exposure of a non-Twilio
credential combined with the unusually high volume of legitimate API requests during the
historical sync. No evidence of actual unauthorised use.
After rotation, attempted to move to region-specific API Keys (more secure, rotatable). This
failed, and the investigation produced a definitive finding:
API Keys (both Standard AND Main) created on the master account CANNOT scope to subaccount
resources. Reading a subaccount's CDRs via the client constructor returns HTTP 401.
TWILIO_ACCOUNT_SID=AC5f68... shared across all regions
TWILIO_AUTH_TOKEN_US1=... US1 token from console.twilio.com
TWILIO_AUTH_TOKEN_AU1=... AU1 token from console.twilio.com/au1
TWILIO_API_BASE_AU1=https://api.sydney.au1.twilio.com
apps/cdr/twilio_client.py get_twilio_client():
Variable TWILIO_AUTH_TOKEN renamed to TWILIO_AUTH_TOKEN_US1. All API key variables removed.
Verified all 8 accounts authenticate on both dev and production. Auth Tokens are region-specific,
so an exposed AU1 token cannot touch US1 and vice versa.