Payment Event Processor — Integration Design
How this system connects to external systems and how data flows between them. It does not restate business goals (Business Requirements) or low-level field/API contracts (Technical Specifications).
1. Systems in scope
| System | Role |
|---|---|
| Stripe | Payment processing, Connect accounts, Checkout, webhooks, Radar, refunds, disputes. |
| Google Firestore | Application ledger, identity, RBAC, idempotency records, audit artifacts. |
| Mailgun | Outbound transactional email (verification). |
| Clients | Browser (WEB), API integrations (CCD); tenant context (CTX) per request. |
2. High-level integration topology
3. Stripe integration
3.1 Outbound (application → Stripe)
Used for merchant and platform operations:
| Use case | Stripe API (conceptual) | When |
|---|---|---|
| Connect onboarding | Account.create (Express), AccountLink.create, Account.retrieve |
POST /api/v1/connect/* |
| Merchant Express Dashboard | Account.create_login_link |
GET /api/v1/connect/express-login-link |
| Hosted checkout | Checkout Session creation (delegated to legacy handler) | POST /api/v1/checkout-sessions |
| Capture / cancel authorization | PaymentIntent.capture, PaymentIntent.cancel |
POST /api/v1/payments/{id}/capture|cancel |
| Refund | Refund.create on connected account |
POST /api/v1/refunds |
Connect account context: Stripe calls that operate on a connected account pass stripe_account=<acct_id> (or equivalent) so the action runs in the merchant’s context.
3.2 Inbound (Stripe → application)
| Channel | Mechanism |
|---|---|
| Webhooks | POST /webhook with Stripe-Signature header |
| Verification | Platform webhook secret (STRIPE_PLATFORM_WEBHOOK_SECRET or equivalent) |
Event flow:
- Stripe delivers event to
POST /webhook. - Handler verifies signature.
- Event is routed to domain handlers (
stripe_app/handlers) and ledger (firestore/payments, etc.). - Idempotency ensures the same
stripe_event_iddoes not double-apply financial effects.
3.3 Canonical vs mirrored state
- Stripe is the runtime authority for charges, refunds, disputes, and Connect account state.
- Firestore is the application ledger and UI mirror: updated by webhooks and by API-initiated actions that Stripe later confirms via webhooks.
4. Firestore integration
4.1 Ledger synchronization pattern
-
Webhook path: Stripe event → verify → idempotency check → transactional update:
payments(snapshot)payment_transactions(append)event_logs(timeline)webhook_events(audit)
-
API path (capture/cancel/refund): Stripe API call → optimistic application notes (
add_api_ledger_entrywhere used) → final state still converges via webhook processing.
4.2 Tenant and identity
- Tenant links users (
users.tenant_id,default_tenant_id) to Connectmerchant_account_idontenants. - Memberships tie RBAC to
(user_id, tenant_id)for CTX.
4.3 Idempotency (client-supplied)
Checkout and refunds use Firestore-backed idempotency records so retries replay the same response or conflict when the fingerprint differs.
5. Mailgun integration
| Direction | Purpose |
|---|---|
| App → Mailgun | Send verification email after signup (link + code). |
| Mailgun → User | User completes verification in browser (/verify-email, /verify-email-code). |
Configuration: MAILGUN_*, APP_BASE_URL (see docs/mailgun_setup.md).
6. Client integration (WEB + CCD + CTX)
6.1 WEB (browser)
- Session cookie (
vispires_session) for dashboard routes. - Same backend may call
/api/v1with Bearer token from login.
6.2 CCD (programmatic)
- JWT:
POST /api/v1/login→Authorization: Bearer <access_token>. - API key:
Authorization: Bearer sk_*orX-API-Key.
6.3 CTX (tenant selection)
- Optional
X-Tenant-Idfor multi-tenant users. - Resolved to
g.tenant_idand membership for RBAC.
7. API v1 — Integration view (by area)
This section describes what each area talks to; request/response tables are in Technical Specifications.
| Area | Stripe | Firestore | Mailgun |
|---|---|---|---|
Discovery / |
— | — | — |
| Health | — | optional ping | — |
| Login / refresh / signup | — | users, tokens, tenants, memberships | signup only |
| Connect | Account, AccountLink, LoginLink, retrieve | tenants, users | — |
| Checkout sessions | Checkout Session (delegated) | idempotency + legacy writes | — |
| List payments | — | payments | — |
| Timeline | — | event_logs (delegated) | — |
| Disputes | — | disputes | — |
| Refunds list | — | refunds | — |
| Refunds create | Refund.create | payment read, idempotency | — |
| Capture / cancel | PaymentIntent capture/cancel | payment + api ledger entry | — |
8. Operational integration (deployment)
- Cloud Run / containers: secrets via environment or Secret Manager.
- Monitoring:
/health,/api/v1/health, liveness/readiness for load balancers. - Stripe dashboard: webhook endpoint URL and signing secret must match deployed URL.
9. Failure and recovery patterns
| Scenario | Behavior |
|---|---|
| Webhook duplicate | Idempotent apply; no duplicate financial effect. |
| API success, webhook delayed | UI may show “initiated” until webhook updates ledger. |
| Stripe API error | HTTP 502 from API routes where applicable; client retries with idempotency keys. |
| Firestore unavailable | Health/readiness degraded; API may return 503/500. |