ADR-002 - AWS SNS for Phone Verification
ADR-002: AWS SNS for Phone Verification
Section titled “ADR-002: AWS SNS for Phone Verification”Date: October 27, 2025
Status: ✅ Accepted
Deciders: Engineering Team
Related: ADR-001 (Centralized Membership), Tier 2 Onboarding
Context
Section titled “Context”CloudAlt requires phone verification for users before they can book stays or create host listings (Tier 2 onboarding). We need a cost-effective, globally scalable SMS verification solution that:
- Works in North America, Europe, Latin America, Asia
- Handles viral growth spikes without catastrophic bills
- Supports 500K+ verifications/month at scale
- Protects bootstrapped startup from cash flow risk
- Requires temporary storage for verification codes (6-digit, 10min TTL)
The “Morning Show Spike” Risk 📺
Section titled “The “Morning Show Spike” Risk 📺”Scenario: CloudAlt gets featured on morning TV
- Day 1-7: 50,000 signups (viral moment)
- 30% complete phone verification = 15,000 SMS
- Months 2-6: Slow revenue ramp while proving unit economics
- Risk: Large cloud bill ($750-$3,000) due in 30 days, potentially before funding/revenue
This is a cash flow killer for pre-funded startups.
Decision
Section titled “Decision”We will use AWS SNS (Simple Notification Service) for SMS delivery and Upstash (Serverless Redis) for verification code storage.
SMS Provider: AWS SNS
Section titled “SMS Provider: AWS SNS”After comprehensive evaluation of 15+ SMS verification providers across multiple cloud platforms (GCP, AWS, Azure, OCI) and specialized SMS services (Twilio, Plivo, MessageBird, Telnyx), AWS SNS emerged as the optimal choice at $0.00645 per SMS.
Key Decision Factors:
-
Cost Leadership: AWS SNS is 87-89% cheaper than alternatives at scale:
- AWS SNS: $0.00645/SMS
- GCP Firebase: $0.06/SMS (9x more expensive)
- Twilio Verify: $0.05/SMS (8x more expensive)
- Supabase Phone Auth: $0.05/SMS (8x more expensive)
-
Viral Spike Protection: Critical for bootstrapped startup cash flow:
- 50K verification spike: AWS = $322, Supabase = $2,500
- Protects against “morning show moment” catastrophic bills
-
Multi-Cloud Philosophy Alignment: Use best CSP for each service:
- Primary: GCP + Supabase (compute, storage, email auth)
- Strategic exception: AWS SNS for SMS (9x cost advantage justifies exception)
-
Scale Economics: At target volumes, savings are massive:
- Couchsurfing scale (583K/month): Save $41,297/year vs alternatives
- 1/4 Airbnb scale (937K/month): Save $66,496/year vs alternatives
- Full Airbnb scale (3.75M/month): Save $265,696/year vs alternatives
-
Multi-Cloud Failover Rejected: GCP Firebase (10K free) → AWS failover saves only $774/year
- Not worth $3K-5K engineering effort (4-6 year payback)
- Firebase free tier becomes insignificant at scale (2% of volume at 500K/month)
-
Market Strategy: Targeting Tier 1 markets (US, Canada, UK, EU, Australia)
- High LTV users ($80-150/night bookings)
- AWS SNS pricing optimal for these regions
- Regional SMS arbitrage (India $0.0005/SMS) irrelevant for low-LTV markets
-
No Hidden Costs: AWS SNS has zero monthly fees, minimums, or setup costs
- Competitors (Twilio, Plivo) add number rental, regulatory fees
- Enterprise providers (Telnyx, Bandwidth) require $5K-10K/month minimums
Implementation Priority: Medium-term (before production launch)
- Immediate priority: Supabase email verification (Tier 1 onboarding) - FREE
- Before launch: AWS SNS phone verification (Tier 2, required before messaging) - Paid
Redis Cache Provider: Upstash
Section titled “Redis Cache Provider: Upstash”For storing verification codes and rate limiting, we evaluated:
Options Considered:
- AWS ElastiCache (t4g.micro): $12.24/month fixed cost
- GCP Memorystore (M1 Basic): $36/month fixed cost
- Upstash (Serverless Redis): FREE up to 300K commands/month, then $0.20 per 100K
- GCP e2-micro (self-hosted Redis): FREE (always-free tier) but requires maintenance
- Django LocMemCache: FREE but loses data on restart
Decision: Start with Upstash, migrate to ElastiCache if needed
Rationale:
- At half Couchsurfing scale (291K verifications/month = 1.16M Redis commands):
- Upstash: $1.73/month
- AWS ElastiCache: $12.24/month
- Savings: $126/year during early growth
- Free tier (300K commands/month) covers ~75K verifications
- Zero setup costs during development
- Used by production companies: Vercel (rate limiting), Clerk (auth sessions), Resend (email API)
- Easy migration path: Change 1 environment variable, redeploy (<1 hour)
- Integration complexity: 1/10 - Drop-in Django cache backend
Migration trigger to AWS ElastiCache:
- Upstash cost exceeds ElastiCache (~600K+ verifications/month)
- Reliability issues impact user experience
- Need 99.9% SLA for enterprise customers
Trade-offs accepted:
- Adds 4th service provider (Supabase, GCP, AWS, Upstash)
- No SLA on free tier (paid plans have 99.9% SLA)
- Phone verification becomes non-critical if Upstash down (browse/search still works)
We will use AWS SNS (Simple Notification Service) for phone verification from Day 1.
Cost Comparison at Critical Thresholds
Section titled “Cost Comparison at Critical Thresholds”SMS Delivery Costs
Section titled “SMS Delivery Costs”| Volume | AWS SNS | Supabase | Twilio | Savings vs Supabase |
|---|---|---|---|---|
| 1,000/month | $0 (free tier) | $50 | $50 | $50 (100%) |
| 10,000/month | $58 | $500 | $450 | $442 (88%) |
| 50,000/month | $316 | $2,500 | $2,250 | $2,184 (87%) |
| 100,000/month | $645 | $5,000 | $4,500 | $4,355 (87%) |
| 500,000/month | $3,225 | $25,000 | $12,100 | $21,775 (87%) |
Redis Cache Costs (for verification codes + rate limiting)
Section titled “Redis Cache Costs (for verification codes + rate limiting)”Assumes 4 Redis commands per verification (SET code, GET code, INCR rate limit, EXPIRE)
| Volume | Redis Commands | Upstash | AWS ElastiCache | GCP Memorystore | Winner |
|---|---|---|---|---|---|
| 75,000/mo | 300K | $0 (free tier) | $12.24 | $36.00 | Upstash ✅ |
| 150,000/mo | 600K | $0.60 | $12.24 | $36.00 | Upstash ✅ |
| 291,000/mo | 1.16M | $1.73 | $12.24 | $36.00 | Upstash ✅ |
| 583,000/mo | 2.33M | $4.06 | $12.24 | $36.00 | Upstash ✅ |
| 1,166,000/mo | 4.66M | $8.73 | $12.24 | $36.00 | Upstash ✅ |
| 1,500,000/mo | 6.0M | $11.60 | $12.24 | $36.00 | Upstash ✅ |
| 2,000,000/mo | 8.0M | $15.60 | $12.24 | $36.00 | ElastiCache ✅ |
Key Insight: Upstash is cheaper until ~1.9M verifications/month. After that, ElastiCache’s fixed cost wins.
Total Phone Verification Cost (SMS + Redis)
Section titled “Total Phone Verification Cost (SMS + Redis)”| Volume | AWS SNS | Upstash | Total | Alternative (SNS + ElastiCache) |
|---|---|---|---|---|
| 75,000/mo | $435 | $0 | $435/mo | $447 (ElastiCache +$12) |
| 291,000/mo | $1,819 | $1.73 | $1,821/mo | $1,831 (ElastiCache +$10) |
| 583,000/mo | $3,703 | $4.06 | $3,707/mo | $3,715 (ElastiCache +$8) |
| 1,166,000/mo | $7,455 | $8.73 | $7,464/mo | $7,467 (ElastiCache +$3) |
| 2,000,000/mo | $12,900 | $15.60 | $12,916/mo | $12,912 (ElastiCache -$4) ✅ |
Migration threshold: ~1.9M verifications/month (when ElastiCache becomes cheaper)
Free Tier Details
Section titled “Free Tier Details”AWS SNS - First 12 months (new AWS account):
- ✅ 1,000 SMS messages FREE per month
- First 1,000 verifications: $0
- Verification #1,001: $0.00645
- Verification #1,002: $0.01290 (first time over $0.01)
After 12 months:
- No free SMS tier
- All SMS paid at $0.00645/message
- Still 87% cheaper than alternatives
Upstash - Always FREE tier:
- ✅ 10,000 Redis commands per day = 300K/month
- Covers ~75K verifications/month
- After free tier: $0.20 per 100K commands
- No time limit (always free)
Rationale
Section titled “Rationale”✅ Advantages
Section titled “✅ Advantages”1. Protection Against Viral Spikes
Morning Show Spike: 15,000 SMS in 7 days
AWS SNS bill: $96.75 ✅ (manageable)Supabase bill: $750 💸 (8x more expensive)Twilio bill: $750 💸 (8x more expensive)Pre-funding, the $650+ difference could be company-killing.
2. 87% Cheaper at EVERY Volume Level
- Not just at scale - saves money from Day 1
- 1,000 verifications: Save $50/month
- 10,000 verifications: Save $442/month
- 500,000 verifications: Save $21,775/month
3. No Engineer Labor Cost Consideration
- In-house engineering team (not outsourced)
- 1-2 days of implementation time acceptable
- Savings start immediately and compound
4. Pay-As-You-Go, No Minimums
- $0 if you send 0 SMS
- No monthly fees
- No contracts
5. Global Coverage
- 240+ countries supported
- Consistent pricing across regions ($0.00645 in North America)
- Reliable delivery rates
6. Full Control
- Custom rate limiting (prevent abuse)
- Fraud detection (block VoIP numbers)
- Custom SMS templates
- No vendor lock-in
Implementation
Section titled “Implementation”Architecture: Tiered Onboarding
Section titled “Architecture: Tiered Onboarding”Tier 1: Email Only (FREE via Supabase)
User signs up → Email verification (Supabase Auth) ↓ Can browse listings Cannot book or hostTier 2: Phone Verification (AWS SNS)
User wants to book/host → Phone verification required ↓ Send 6-digit code via AWS SNS ↓ User enters code ↓ Verified → Can book/hostThis approach reduces verification costs by 50-70% since many users may never complete Tier 2 (just browsing).
Technical Flow
Section titled “Technical Flow”# Send verification codePOST /api/v1/phone/send-code/{ "phone_number": "+14155551234"}
Response:{ "success": true, "expires_in": 600, # 10 minutes "attempts_remaining": 3}
# Verify codePOST /api/v1/phone/verify-code/{ "phone_number": "+14155551234", "code": "123456"}
Response:{ "success": true, "verified": true, "tier_completed": 2, "can_book": true}Code Storage: Django Cache + Redis
Section titled “Code Storage: Django Cache + Redis”Development: Django in-memory cache (free) Production: Redis/ElastiCache ($12-50/month depending on scale)
# Store verification code with 10-minute expirycache.set(f"verify_code:{phone_number}", code, timeout=600)
# Rate limiting: 3 attempts per phone per daycache.set(f"verify_attempts:{phone_number}", attempts, timeout=86400)Fraud Prevention
Section titled “Fraud Prevention”- Rate Limiting: Max 3 SMS per phone per 24 hours
- reCAPTCHA: Required before sending code (prevent bots)
- VoIP Detection: Block Twilio/Google Voice numbers (optional)
- Country Allowlist: Start with high-value markets, expand gradually
- Phone Number Format Validation: E.164 format required
Cost Projections
Section titled “Cost Projections”6-Month Pre-Revenue Period (Bootstrapped Startup)
Section titled “6-Month Pre-Revenue Period (Bootstrapped Startup)”Assumptions:
- Month 1: Viral spike (50K signups, 15K phone verifications)
- Months 2-6: Slow growth (5K signups/month, 1.5K phone verifications/month)
AWS SNS:
- Month 1 (viral): $90.68
- Months 2-6: $48.38 total
- Redis: $60 (5 months)
- Total: $199.06 ✅
Supabase:
- Month 1 (viral): $750
- Months 2-6: $375 total
- Total: $1,125 💸
Savings: $925.94 in critical pre-revenue period
This could be the difference between survival and shutdown for a bootstrapped startup.
Year 1 Projections
Section titled “Year 1 Projections”Conservative Growth:
- Total verifications: 120,000 in year 1
AWS SNS:
- First 12 months benefit from free tier
- 12,000 SMS free (1,000/month × 12)
- 108,000 SMS × $0.00645 = $696.60
- Redis: $144 (12 months × $12)
- Total Year 1: $840.60 ✅
Supabase:
- 120,000 × $0.05 = $6,000 💸
Year 1 Savings: $5,159.40
Scale Projections (Year 2-3)
Section titled “Scale Projections (Year 2-3)”Year 2: 500,000 verifications
- AWS SNS: $3,225 + Redis $588 = $3,813/year
- Supabase: $25,000/year
- Savings: $21,187/year
Year 3: 1,000,000 verifications
- AWS SNS: $6,450 + Redis $1,176 = $7,626/year
- Twilio Verify (volume pricing): $19,000/year
- Savings: $11,374/year
Consequences
Section titled “Consequences”Immediate Changes (Phase 4)
Section titled “Immediate Changes (Phase 4)”1. Add phone_number field to MemberProfile:
phone_number = models.CharField(max_length=20, blank=True)phone_country_code = models.CharField(max_length=5, default='+1')verified_phone = models.BooleanField(default=False)phone_verified_at = models.DateTimeField(null=True, blank=True)2. AWS SNS Setup:
- Create AWS account (or use existing)
- Enable SNS in region (us-east-1 recommended for US)
- Create IAM user with SNS publish permissions
- Store credentials in Django settings (environment variables)
3. Django Cache Configuration:
- Development: In-memory cache
- Production: Redis on ElastiCache or self-hosted
4. New API Endpoints:
POST /api/v1/phone/send-code/- Send verification codePOST /api/v1/phone/verify-code/- Verify code- Rate limiting middleware
- reCAPTCHA integration
5. Update Tier 2 Onboarding:
- Require phone verification before allowing bookings/hosting
- Update MemberProfile.tier_completed field
- Add phone verification status to profile responses
Alternatives Considered
Section titled “Alternatives Considered”Alternative 1: Multi-Cloud Failover (GCP Firebase → AWS SNS)
Section titled “Alternative 1: Multi-Cloud Failover (GCP Firebase → AWS SNS)”Concept:
- Use GCP Firebase’s 10,000 free SMS/month first
- Automatically failover to AWS SNS after Firebase free tier exhausted
- Theoretical max savings: $64.50/month ($774/year)
Analysis at Scale:
| Monthly Verifications | Firebase Saves | Annual Savings | Engineering Cost | Payback Period |
|---|---|---|---|---|
| 50,000 | $64.50/month | $774/year | $3,000-5,000 | 4-6 years |
| 500,000 | $64.50/month | $774/year | $3,000-5,000 | 4-6 years |
| 3,750,000 (Airbnb scale) | $64.50/month | $774/year | $3,000-5,000 | 4-6 years |
Key insight: Firebase’s 10K free tier becomes increasingly insignificant as scale grows:
- At 500K/month: 10K represents only 2% of volume
- Savings remain constant at $64.50/month regardless of total volume
Pros:
- ✅ Maximizes free tier usage (10K Firebase + 1K AWS = 11K free/month)
- ✅ Multi-cloud resilience (automatic failover if one provider fails)
- ✅ No vendor lock-in
Cons:
- ❌ Savings don’t scale ($774/year at ANY volume)
- ❌ 2-3 days engineering effort ($3,000-5,000 cost)
- ❌ Additional complexity (two SDKs, two APIs, failover logic)
- ❌ Maintenance burden (monitor two providers)
- ❌ 4-6 year payback period
Deferred: Will reconsider when:
- Regional providers offer 10x cost savings (e.g., India-specific SMS at $0.0005)
- WhatsApp Business API adoption justifies multi-channel strategy
- Volume exceeds 10M/month and negotiated enterprise pricing becomes available
Alternative 2: Supabase Phone Auth
Section titled “Alternative 2: Supabase Phone Auth”Pros:
- ✅ Easiest integration (already using Supabase for email auth)
- ✅ No custom verification code needed
- ✅ Handles rate limiting automatically
Cons:
- ❌ $0.05 per SMS (8x more expensive than AWS)
- ❌ No volume discounts visible
- ❌ $750-$3,000 bills during viral spikes
- ❌ Annual cost: $6,000-$300,000+ depending on scale
Rejected: Cost too high for bootstrapped startup, especially during pre-revenue growth.
Alternative 2: Twilio Verify API
Section titled “Alternative 2: Twilio Verify API”Pros:
- ✅ Best-in-class features (voice fallback, fraud detection)
- ✅ Volume pricing (drops to $0.02 at 100K+)
- ✅ Excellent documentation and SDKs
Cons:
- ❌ $0.05 base price (8x more expensive than AWS)
- ❌ Volume discounts only kick in at 100K+ verifications
- ❌ Still expensive for small startups: $450-$500/month at 10K verifications
Deferred: Good option for scale (500K+), but AWS is cheaper at all volumes. Reconsider if AWS SNS reliability becomes an issue.
Alternative 3: Firebase Phone Auth
Section titled “Alternative 3: Firebase Phone Auth”Pros:
- ✅ 10,000 free verifications/month (generous free tier)
- ✅ Great mobile SDKs (iOS/Android)
- ✅ Integrated with Firebase Auth ecosystem
Cons:
- ❌ $0.06 per verification after 10K (more expensive than AWS)
- ❌ Would need Firebase + Supabase (two auth systems)
- ❌ Less backend control
Rejected: AWS SNS is simpler (one less service) and cheaper after 10K verifications.
Alternative 4: Vonage (Nexmo)
Section titled “Alternative 4: Vonage (Nexmo)”Pros:
- ✅ Similar features to Twilio
- ✅ Good international coverage
Cons:
- ❌ Most expensive option ($0.08 per SMS, no volume discounts until 100K)
- ❌ $32,000/month at 500K verifications
Rejected: No cost advantage over any other option.
Success Metrics
Section titled “Success Metrics”Cost Efficiency
Section titled “Cost Efficiency”- Target: Stay under $500/month for first 50K verifications
- Target: Stay under $1,000/month for first 100K verifications
- Target: Verify phone costs remain <5% of revenue at scale
User Experience
Section titled “User Experience”- Target: 95%+ SMS delivery rate globally
- Target: <30 second delivery time (99th percentile)
- Target: <5% user drop-off during phone verification
Fraud Prevention
Section titled “Fraud Prevention”- Target: <1% of verifications are fraudulent/abuse
- Target: Block 100% of known VoIP numbers (if policy implemented)
- Target: Successful rate limiting (no user can trigger >3 SMS/day)
Migration Plan
Section titled “Migration Plan”Phase 1: Implement AWS SNS (Now)
Section titled “Phase 1: Implement AWS SNS (Now)”- Set up AWS account and IAM credentials
- Build send-code and verify-code endpoints
- Implement rate limiting and fraud detection
- Test with development phone numbers
Phase 2: Frontend Integration (Week 2)
Section titled “Phase 2: Frontend Integration (Week 2)”- Build Tier 2 onboarding form in Pink Guest mobile app
- Phone number input with country code selector
- SMS code entry screen
- Error handling and retry logic
Phase 3: Production Launch (Week 3)
Section titled “Phase 3: Production Launch (Week 3)”- Enable AWS SNS in production
- Monitor delivery rates and costs
- Iterate on rate limiting thresholds based on abuse patterns
Phase 4: Optimization (Month 2-3)
Section titled “Phase 4: Optimization (Month 2-3)”- Add WhatsApp verification for international markets (if needed)
- Implement VoIP detection (if fraud becomes an issue)
- A/B test different SMS templates for best conversion
Phase 5: Future Enhancements (Month 6+)
Section titled “Phase 5: Future Enhancements (Month 6+)”- Voice call fallback for landlines
- Multi-language SMS templates
- SMS cost tracking dashboard
- Auto-scaling Redis based on verification volume
Future Considerations
Section titled “Future Considerations”When to Reconsider Multi-Cloud Strategy
Section titled “When to Reconsider Multi-Cloud Strategy”Threshold 1: Regional Provider Arbitrage (>$10K/year savings)
If a significant portion of users are in regions with dramatically cheaper local SMS providers:
Example: India-focused growth
- 500K monthly verifications in India
- Local provider (e.g., TextLocal): $0.0005/SMS
- AWS SNS: $0.00645/SMS
- Savings: 500K × ($0.00645 - $0.0005) = $2,975/month = $35,700/year ✅
- Justifies multi-cloud implementation
Example: Latin America WhatsApp adoption
- 80% of users prefer WhatsApp (conversation-based pricing: $0.005)
- Traditional SMS: $0.00645
- 1M monthly verifications via WhatsApp
- Savings: 800K × ($0.00645 - $0.005) = $1,160/month = $13,920/year ✅
- Justifies WhatsApp Business API integration
Threshold 2: Enterprise Volume (>10M verifications/month)
Section titled “Threshold 2: Enterprise Volume (>10M verifications/month)”At massive scale, negotiate custom enterprise pricing:
Example: 10M verifications/month
- Twilio Enterprise: $0.015/SMS (negotiated)
- AWS SNS: $0.00645/SMS (standard)
- Savings by staying with AWS: 10M × ($0.015 - $0.00645) = $86,500/month ✅
- Or negotiate with both and choose best offer
Threshold 3: New Free Tier Provider Emerges
Section titled “Threshold 3: New Free Tier Provider Emerges”Monitor for new providers with generous free tiers:
Hypothetical: Provider offers 100K free/month
- 100K vs AWS 1K free = 99K additional free verifications
- Savings: 99K × $0.00645 = $638.55/month = $7,662/year ✅
- Justifies multi-cloud implementation
Monitoring and Alerts
Section titled “Monitoring and Alerts”Cost Alerts
Section titled “Cost Alerts”AWS CloudWatch Alarms:- Alert if monthly SMS spend exceeds $100 (first 3 months)- Alert if monthly SMS spend exceeds $500 (months 4-12)- Alert if daily SMS spend exceeds $50 (possible abuse)Performance Alerts
Section titled “Performance Alerts”Django Monitoring:- Alert if SMS delivery rate drops below 90%- Alert if average delivery time exceeds 60 seconds- Alert if verification endpoint errors exceed 5%Security Alerts
Section titled “Security Alerts”Rate Limiting:- Log and alert if same phone attempts >3 verifications/day- Log and alert if same IP requests >10 codes/hour- Monitor for patterns indicating bot activityReferences
Section titled “References”- AWS SNS Pricing
- AWS SNS SMS Best Practices
- Django Cache Framework
- E.164 Phone Number Format
- ADR-001: Centralized BU-Level Membership
Revision History
Section titled “Revision History”| Date | Version | Changes | Author |
|---|---|---|---|
| 2025-10-27 | 1.0 | Initial decision: AWS SNS for phone verification | Engineering Team |
| 2025-10-27 | 1.1 | Added Redis cache provider decision: Upstash (serverless) for early stage, with migration path to AWS ElastiCache at scale | Engineering Team |