feat(billing): add BillingService.open_customer_portal + GET endpoint

Authed users can now request a Stripe-hosted Customer Portal URL for card
updates and cancellation via GET /api/v1/billing/portal-session. The path is
already in both _SUBSCRIPTION_GUARD_ALLOWLIST and _EMAIL_VERIFICATION_ALLOWLIST
so canceled or unverified-past-grace users can still update billing.

- Returns 503 with {"error": "stripe_not_configured"} when STRIPE_SECRET_KEY unset.
- Returns 400 with {"error": "no_stripe_customer"} when account has no
  stripe_customer_id (must complete checkout first).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-06 19:55:42 -04:00
parent f918b766b0
commit 2f8ec3775e
4 changed files with 131 additions and 1 deletions

View File

@@ -13,6 +13,10 @@ class CheckoutSessionResponse(BaseModel):
url: str
class BillingPortalSessionResponse(BaseModel):
url: str
class SubscriptionState(BaseModel):
status: str
plan: str