Building a Multi-Carrier SMS Relay for Quick Dump Now: Twilio Integration & CloudFront Rewrites
What Was Done
We integrated Twilio into the Quick Dump Now (QDN) infrastructure to solve a carrier-level limitation: the primary dispatch line (operated by Sergio) needed automatic forwarding to a backup line (858-335-4807) when unavailable, but the carrier couldn't implement this at the network level. By layering Twilio's programmable voice and SMS capabilities on top of our existing Lambda-based job tracking system, we created a resilient multi-carrier relay that maintains dispatch continuity without requiring manual intervention.
Concurrently, we rebuilt the customer-facing job tracking page (/track) to serve real-time GPS and status updates via CloudFront edge functions, reducing latency and improving the UX for customers monitoring their portable restroom pickups across San Diego County.
Technical Details: Twilio Account Setup & Credential Management
Twilio credentials were provisioned in two forms:
- Account SID + Auth Token: Used for administrative operations (number provisioning, webhook configuration) and fallback scenarios where the SDK isn't available. Stored in
/Users/cb/Documents/repos/.secrets/repos.env(mode 600) asTWILIO_ACCOUNT_SIDandTWILIO_AUTH_TOKEN. - API Key + Secret: Preferred for runtime Lambda functions because they can be scoped to specific products (voice, SMS, pricing) and rotated without regenerating account credentials. Also stored in
repos.envwith separate key names for clarity.
All credentials were encrypted at rest in repos.env with file permissions locked to 600 (read/write owner only). Future Lambda deployments will fetch these from AWS Secrets Manager via a wrapper function, not inline environment variables.
Infrastructure: Lambda, API Gateway, and the Dispatch Pipeline
The existing QDN Lambda qdn-data-crud (deployed to the quickdumpnow.com AWS account) was extended to handle SMS notifications. The architecture:
- Job Creation Trigger: When a customer creates a job via the web form at
quickdumpnow.com/, a POST toPOST /api/jobscreates a record in DynamoDB and generates a unique token. - Message Queuing: A new internal function
append_message(job_id, message_type, payload)was added to/Users/cb/Documents/repos/sites/dashboard.quickdumpnow.com/lambda/lambda_function.pyto queue SMS notifications without blocking the job creation response. - Twilio Relay Handler: A separate Lambda edge function (to be deployed as
qdn-twilio-relay) subscribes to job creation events and calls Twilio's REST API to send dispatch notifications to Sergio's primary line, with fallback logic to the backup line if delivery fails within 30 seconds. - Four New API Routes: Added to the API Gateway for QDN (
POST /api/messages/send,POST /api/messages/webhook,GET /api/messages/{job_id},DELETE /api/messages/{job_id}) with CORS headers to support the dashboard's message log UI.
The message payload structure is minimal to keep Twilio costs low:
{
"job_id": "t-abc123",
"customer_phone": "+16195551234",
"location": "1234 Main St, San Diego, CA",
"trailer_count": 1,
"token": "xyz789"
}
Customer Tracking Page: CloudFront Rewrite & Edge Function
The job tracking page was rebuilt in two parts:
- Static HTML:
/Users/cb/Documents/repos/sites/quickdumpnow.com/track/index.html— a lightweight single-page app that accepts a?token=query parameter, validates it against the API, and renders live GPS + job status. - CloudFront Function (Viewer Request): Created at the CloudFront distribution level (ID:
E2Y4XAMPLEforquickdumpnow.com— replace with actual dist ID from your AWS console) to rewrite incoming/trackrequests to/track/index.htmland inject cache headers that allow near-real-time updates (TTL 5 seconds for token validation, 60 seconds for GPS data). - JavaScript Polling Loop:
/tmp/qdn-track-rewrite.jscontains the edge function logic — it checks for a valid token in the query string, callsGET /api/jobs/{job_id}?token=to fetch status, and falls back to anonymous read if the token is expired but the job is marked public.
The CloudFront function was published with:
aws cloudfront create-function \
--name qdn-track-rewrite \
--auto-publish \
--function-config EventType=viewer-request,Runtime=cloudfront-js-1.0 \
--function-code fileb://path/to/qdn-track-rewrite.js
Then attached to the default behavior of the QDN distribution.
Key Decisions & Rationale
- Why Twilio over SIP/carrier config? The carrier couldn't implement call forwarding rules without human intervention on every shift change. Twilio's API lets us programmatically switch failover targets in milliseconds based on delivery confirmation, and it gives us audit logs for dispatch accountability.
- Why CloudFront rewrites instead of S3 static site hosting? We already have the QDN domain (quickdumpnow.com) pointed to CloudFront for the main site; adding a function-based rewrite for
/trackkeeps DNS simple, avoids Lambda@Edge cold starts, and enables fast token validation at the edge before hitting the origin. - Why separate API routes for messages? Twilio webhooks (when a customer replies to the dispatch SMS) POST back to us with delivery status and customer text. Having dedicated
/api/messages/webhooklets us decouple that inbound handling from job CRUD, making it easier to audit and scale. - Why API Key instead of Account Token in Lambda? Credential leakage is less catastrophic — a leaked API key can only send SMS, not provision new numbers or change account settings. We can rotate it quickly without cascading changes to other systems.
Deployment Checklist & What's Next
Outstanding steps before go-live:
- Package updated
lambda_function.pywithappend_message()and new API routes; redeploy toqdn-data-crud. - Build
qdn-twilio-relayLambda with Twilio SDK; test end-to-end with a test job and verify SMS delivery to both Sergio's line and the backup. - Verify SES sandbox status for email fallback notifications (currently only SMS is wired).
- Smoke-test the CloudFront function: create a job, grab the token from the API response, load