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).
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)
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
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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:
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
Billing history
Manage subscription CTA
/account/(or billing section)Backend dependency (coordinate with finance app)
portal_url(if not already shipped after #21).envexamples as neededUX / edge cases
Tests
Acceptance criteria
Out of scope
Notes
finance(chat_backend#21)Companions: