Skip to content

ux(payments): show renewal verification / lapsed billing state instead of generic Upgrade CTA #4771

Description

@koala73

Split from the payment reliability review around #4765.

Problem

When local entitlement state falls back to free, the product currently behaves like the user is simply a free user:

  • Premium panels are re-gated through panel-layout.ts:updatePanelGating().
  • API/browser calls surface generic messages such as Pro subscription required, Upgrade required, or API access requires an active subscription.
  • The only explicit billing banner is for subscription.status === on_hold in payment-failure-banner.ts.

That misses an important state: the customer may still be paying in Dodo, but our local renewal state is stale because a webhook was missed or exhausted. In that case, generic upgrade copy is misleading and can push the customer toward duplicate checkout or support confusion.

Proposed work

Introduce explicit billing states for the frontend/API boundary, separate from plain free-tier gating.

Suggested states:

  • free - never paid / no active subscription evidence.
  • active - entitlement valid now.
  • on_hold - payment failed / retry window, existing red banner behavior.
  • renewal_verification_pending - local paid subscription appears stale and reconciliation is in progress or queued.
  • renewal_verification_failed - provider check failed; ask user to refresh/contact support/manage billing.
  • lapsed - provider confirms no active paid coverage remains.

Acceptance criteria

  • A user with stale local paid evidence does not see only the generic Upgrade to Pro CTA while renewal verification is pending/failed.
  • UI shows clear copy: checking renewal, retry/refresh, manage billing, or contact support depending on state.
  • API/programmatic responses expose a stable error code or detail for renewal-verification vs true free/lapsed state.
  • on_hold payment-failure banner remains intact and is not conflated with missed-renewal reconciliation.
  • Tests cover panel gating/copy for free, active, on_hold, renewal verification pending/failed, and lapsed.

Related

Priority: P1. This is customer-trust UX: do not tell a paying user to upgrade when the real state is we are verifying your renewal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High priority, fix soonpaymentPayment, billing, subscription, checkout, and entitlement lifecycle

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions