2.5 KiB
2.5 KiB
Payment & Billing Flow (Provider‑agnostic)
Last Updated: 2025-01-17
Phase: Phase 0 (Planning)
Status: Draft — finalize in Phase 1
Owner: Backend Architect
References:
/docs/project-overview.md/docs/backend/architecture.md/docs/backend/api-design.md/docs/backend/security.md
Single source of truth for subscription billing with an external payment provider. No raw card data is handled by our app.
1) High-Level Flow
- Frontend calls backend to create a Checkout/Portal Session (
POST /billing/session) with tenant/context. - Backend creates/updates the Customer (if needed) and Session at the payment provider; returns
sessionUrl. - User completes checkout on provider‑hosted page.
- Payment provider sends webhooks (e.g., subscription created/updated/canceled).
- Backend verifies signatures, updates subscription state in DB, and logs events (
BILLING_UPDATED). - Frontend reads subscription status from backend (
/billing/status) — webhook‑driven source of truth.
2) Required Endpoints
POST /billing/session— init checkout/plan change. Request: tenant ID inferred from auth; plan/tier; success/cancel URLs. Response:sessionUrl.GET /billing/status— return subscription status, current plan, renewal/cancel info (cached from webhook‑driven DB state).POST /billing/webhooks/provider— verify signature; idempotent upsert of subscription state; update tenant access.
3) Data Model Notes
- Store provider customer ID, subscription ID, price/plan, status, current period dates, cancel_at/canceled_at, seats (if applicable).
- All writes must be idempotent (webhook retries). Use provider event IDs for dedupe.
- Permissions are enforced per tenant based on subscription status.
4) States & Mapping (common)
trialing,active,past_due,canceled,incomplete/incomplete_expired,unpaid→ map to internal states that drive access. Deny critical actions when subscription is inactive.
5) Security & Compliance
- Verify webhook signatures with provider secret; reject if invalid; log failures with trace IDs.
- Do not log sensitive payloads; store only necessary billing identifiers.
- Expose no card data; rely on provider‑hosted UIs (Checkout/Portal) for payment method management.
6) Frontend UX Notes
- Use provider trust cues and clear statuses after redirect: success/pending/fail with recovery (retry checkout, contact support).
- All status displays must read from backend (webhook‑driven), not query params.