46 lines
2.5 KiB
Markdown
46 lines
2.5 KiB
Markdown
# 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
|
||
1. Frontend calls backend to create a Checkout/Portal Session (`POST /billing/session`) with tenant/context.
|
||
2. Backend creates/updates the Customer (if needed) and Session at the payment provider; returns `sessionUrl`.
|
||
3. User completes checkout on provider‑hosted page.
|
||
4. Payment provider sends webhooks (e.g., subscription created/updated/canceled).
|
||
5. Backend verifies signatures, updates subscription state in DB, and logs events (`BILLING_UPDATED`).
|
||
6. 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.
|