Add Account billing section + Stripe Customer Portal (plan changes / cancellations) #33

Closed
opened 2026-07-27 04:07:43 -07:00 by westfarn · 1 comment
Owner

Summary

Follow-on from the Stripe finance MVP: surface billing on the Account page and let users manage plan changes, payment methods, and cancellations via Stripe’s hosted Customer Portal (no card collection in-app).

Related:

chat_backend#21 explicitly deferred “Full Customer Portal UI for plan changes/cancellations” as follow-on work.

Context

Checkout + webhook ledger land in #21 / #31. After payment, users need a place in-app to:

  • See current plan / subscription status
  • Review billing history (invoices & payments)
  • Change plan, update payment method, or cancel — via Stripe Customer Portal redirect

Account UI today (/account/Account2) covers profile / company users / theme — no billing section yet.

Backend already exposes authenticated list APIs from #21:

  • GET /api/finance/invoices/
  • GET /api/finance/payments/

Customer Portal session creation was out of scope for #21 and likely still needs a backend endpoint (e.g. POST /api/finance/portal/ returning a hosted portal URL).

Requirements

Account page — Billing section

On /account/ (Account2), add a Billing section (same visual language as existing glass cards) that includes:

  • Billing information / current plan

    • Plan name / product (from subscription settings or invoice description)
    • Status (active, past_due, canceled, unpaid, etc. as available)
    • Amount / interval / currency when known
    • Next renewal / period end when available
    • Clear empty / unpaid state for users who registered but have not completed Checkout (#31)
  • Billing history

    • Table (or equivalent) of the user’s invoices and/or payments from finance APIs
    • Columns such as date, description, amount, status, provider refs as useful
    • Loading, empty, and error states consistent with existing Account UX
  • Manage subscription CTA

    • Button that requests a Stripe Customer Portal session from the backend and redirects to Stripe’s hosted portal
    • Used for plan changes, payment method updates, and cancellations
    • Return URL lands back on /account/ (or billing section)
    • Do not collect or display raw card numbers in our UI

Backend dependency (coordinate with finance app)

  • Authenticated API to create a Stripe Billing Portal session and return portal_url (if not already shipped after #21)
  • Reuse existing invoice/payment list endpoints for history
  • Document any new env/settings (portal return URL, allowed portal configuration) in backend .env examples as needed

UX / edge cases

  • Unauthenticated users remain blocked by existing account route guard
  • Users with no Stripe customer / no paid subscription: show helpful copy + path to pay (Checkout / sign-up flow from #31) instead of a dead portal button
  • Portal / API failures: visible error, no silent fail

Tests

  • Billing section renders plan summary and history from mocked finance APIs
  • “Manage billing” happy path redirects to returned portal URL
  • Empty / unpaid / error states covered

Acceptance criteria

  • Account page has a Billing section with current plan / billing info
  • Billing history lists the user’s invoices and/or payments
  • CTA opens Stripe Customer Portal (hosted) for plan changes, payment method, and cancellation
  • No card details collected in our UI
  • Return from portal lands back in Account / billing
  • Empty and error states handled clearly (incl. unpaid / no subscription)
  • Tests cover history render + portal redirect happy path
  • Linked from / references chat_backend#21 and chat_web_app#31

Out of scope

  • Building a fully custom in-app plan picker / cancel wizard (prefer Stripe Portal)
  • Token quota enforcement (see chat_backend#17)
  • Replacing Checkout / sign-up flow (#31)

Notes

  • Card entry and subscription management UI stay on Stripe
  • Invoice/Payment persistence and webhooks remain owned by finance (chat_backend#21)
  • Minimal MVP: single subscription product from backend settings is fine; portal handles change/cancel
## Summary Follow-on from the Stripe finance MVP: surface billing on the Account page and let users manage plan changes, payment methods, and cancellations via Stripe’s hosted **Customer Portal** (no card collection in-app). Related: - Backend finance + Checkout / invoices / payments: ai_ml_operations/chat_backend#21 - Self-serve sign-up → Checkout: ai_ml_operations/chat_web_app#31 `chat_backend`#21 explicitly deferred “Full Customer Portal UI for plan changes/cancellations” as follow-on work. ## Context Checkout + webhook ledger land in #21 / #31. After payment, users need a place in-app to: - See current plan / subscription status - Review billing history (invoices & payments) - Change plan, update payment method, or cancel — via Stripe Customer Portal redirect Account UI today (`/account/` → `Account2`) covers profile / company users / theme — no billing section yet. Backend already exposes authenticated list APIs from #21: - `GET /api/finance/invoices/` - `GET /api/finance/payments/` Customer Portal session creation was out of scope for #21 and likely still needs a backend endpoint (e.g. `POST /api/finance/portal/` returning a hosted portal URL). ## Requirements ### Account page — Billing section On `/account/` (`Account2`), add a **Billing** section (same visual language as existing glass cards) that includes: - **Billing information / current plan** - Plan name / product (from subscription settings or invoice description) - Status (active, past_due, canceled, unpaid, etc. as available) - Amount / interval / currency when known - Next renewal / period end when available - Clear empty / unpaid state for users who registered but have not completed Checkout (#31) - **Billing history** - Table (or equivalent) of the user’s invoices and/or payments from finance APIs - Columns such as date, description, amount, status, provider refs as useful - Loading, empty, and error states consistent with existing Account UX - **Manage subscription CTA** - Button that requests a Stripe Customer Portal session from the backend and redirects to Stripe’s hosted portal - Used for plan changes, payment method updates, and cancellations - Return URL lands back on `/account/` (or billing section) - Do **not** collect or display raw card numbers in our UI ### Backend dependency (coordinate with finance app) - Authenticated API to create a Stripe Billing Portal session and return `portal_url` (if not already shipped after #21) - Reuse existing invoice/payment list endpoints for history - Document any new env/settings (portal return URL, allowed portal configuration) in backend `.env` examples as needed ### UX / edge cases - Unauthenticated users remain blocked by existing account route guard - Users with no Stripe customer / no paid subscription: show helpful copy + path to pay (Checkout / sign-up flow from #31) instead of a dead portal button - Portal / API failures: visible error, no silent fail ### Tests - Billing section renders plan summary and history from mocked finance APIs - “Manage billing” happy path redirects to returned portal URL - Empty / unpaid / error states covered ## Acceptance criteria - [ ] Account page has a Billing section with current plan / billing info - [ ] Billing history lists the user’s invoices and/or payments - [ ] CTA opens Stripe Customer Portal (hosted) for plan changes, payment method, and cancellation - [ ] No card details collected in our UI - [ ] Return from portal lands back in Account / billing - [ ] Empty and error states handled clearly (incl. unpaid / no subscription) - [ ] Tests cover history render + portal redirect happy path - [ ] Linked from / references chat_backend#21 and chat_web_app#31 ## Out of scope - Building a fully custom in-app plan picker / cancel wizard (prefer Stripe Portal) - Token quota enforcement (see chat_backend#17) - Replacing Checkout / sign-up flow (#31) ## Notes - Card entry and subscription management UI stay on Stripe - Invoice/Payment persistence and webhooks remain owned by `finance` (chat_backend#21) - Minimal MVP: single subscription product from backend settings is fine; portal handles change/cancel
Author
Owner

Companions:

Companions: - Backend finance MVP (Checkout / invoices / payments): ai_ml_operations/chat_backend#21 — https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/21 - Self-serve sign-up → Checkout: ai_ml_operations/chat_web_app#31 — https://git.aimloperations.com/ai_ml_operations/chat_web_app/issues/31
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ai_ml_operations/chat_web_app#33