
Building Payment Systems for Emerging Markets: Lessons from 10+ FastAPI Production Deployments in Mexico
The real test of any payment platform isn't handling Stripe webhooks—it's navigating the messy reality of emerging markets where cash is king and regulations are local.
A developer just shared their battle-tested insights from running a FastAPI payment platform in Mexico for two years, handling SPEI transfers, OXXO convenience store payments, and crypto on-ramps. What makes this compelling isn't just another "I built with FastAPI" story—it's how Mexico's payment ecosystem exposes architectural decisions that most tutorials completely miss.
Why Mexico Changes Everything
Most payment integration guides assume your users have credit cards and reliable internet. Mexico's reality is different:
- SPEI (Sistema de Pagos Electrónicos Interbancarios) handles interbank transfers but requires CNBV regulatory compliance
- OXXO Pay lets users pay bills with cash at 20,000+ convenience stores across the country
- Crypto on-ramps serve as alternative banking for populations with limited traditional banking access
This isn't just about adding another PSP to your config file. Each payment method brings different latency patterns, failure modes, and user expectations.
<> "Building payment platforms in emerging markets exposes unique challenges: local regulations, high-latency networks, cash-based economies, and crypto volatility—things global Stripe tutorials completely overlook."/>
The Multi-PSP Architecture That Actually Works
After 10+ production deployments, the author discovered that PSP vendor lock-in kills you in emerging markets. Payment providers come and go, regulations shift, and backup options aren't luxury—they're survival.
Here's the extensible pattern that emerged:
1from fastapi_payments import FastAPIPayments
2
3# Load PSP configs dynamically
4payments = FastAPIPayments(config={
5 "stripe": {"secret_key": "...", "webhook_secret": "..."},
6 "oxxo_provider": {"api_key": "...", "merchant_id": "..."},
7 "spei_provider": {"clabe_account": "...", "cert_path": "..."}
8})The key insight: treat payment methods as first-class citizens, not just PSP configurations. Cash payments have fundamentally different flows than card payments, and your architecture should reflect that.
Handling Mexico-Specific Async Patterns
FastAPI's async capabilities become essential when dealing with Mexico's payment landscape. OXXO payments can take days to complete (users physically visit stores), SPEI transfers process during banking hours, and crypto prices fluctuate by the minute.
The production-tested webhook pattern:
1from fastapi import BackgroundTasks
2import asyncio
3from sqlalchemy.ext.asyncio import AsyncSession
4
5@app.post("/webhooks/oxxo")
6async def handle_oxxo_webhook(
7 webhook_data: dict,
8 background_tasks: BackgroundTasks,The Production Checklist That Matters
After multiple deployments, certain patterns proved non-negotiable:
Event-Driven Everything: Use RabbitMQ or similar for payment state changes. When OXXO payments can take 72 hours to confirm, you need reliable async processing.
Regulatory Compliance by Design: SPEI transfers require specific data retention and audit trails. Build this into your models from day one:
1class SPEITransfer(BaseModel):
2 clabe_origin: str
3 clabe_destination: str = Field(..., regex=r'^\d{18}$') # CLABE validation
4 amount: Decimal = Field(..., decimal_places=2)
5 concept: str = Field(..., max_length=40) # SPEI limit
6 audit_trail: List[AuditEvent] = []
7
8 def add_audit_event(self, event_type: str, details: dict):
9 self.audit_trail.append(AuditEvent(
10 timestamp=datetime.utcnow(),
11 event_type=event_type,
12 details=details
13 ))Graceful PSP Degradation: When your primary SPEI provider goes down during banking hours, you need instant failover. Design your payment service with circuit breakers:
1from circuitbreaker import circuit
2
3class PaymentOrchestrator:
4 @circuit(failure_threshold=5, recovery_timeout=30)
5 async def create_spei_transfer(self, transfer_data):
6 try:
7 return await self.primary_spei_provider.create_transfer(transfer_data)
8 except Exception:
9 return await self.backup_spei_provider.create_transfer(transfer_data)Why This Matters Beyond Mexico
This isn't just about Mexico—it's about building payment systems that work in the real world. The patterns that emerge from handling OXXO cash payments and SPEI regulations make your platform more resilient everywhere:
- Async-first architecture handles high latency gracefully
- Multi-PSP design prevents vendor lock-in disasters
- Regulatory compliance patterns prepare you for any market
- Event-driven state management scales beyond payment processing
If your payment platform only works with Stripe in low-latency environments, you're not building a platform—you're building a prototype. The chaos of emerging markets forces you to architect systems that actually scale.
Next steps: Start with the multi-PSP pattern even if you're only using one provider today. Build webhook verification from day one. And if you're targeting any market outside the US/EU, study how cash-based payments change your entire user experience assumptions.

