Skip to content

Billing: USD to EUR migration flow for members who buy workspaces #131

Open

Description

@sre-helmcode

Context

Stripe locks a customer's currency on their first invoice. Workspace slots are sold EUR-only (see handoff-workspace-tiers-2026-09-18.md), so a member whose customer already bills in USD cannot add a EUR slot item or check out a EUR slot on the same customer.

Current state

  • 121 members still bill in USD: 99 inference at $75/month and 22 community at $14.99/month.
  • Temporary behaviour (shipping now): slot checkout for a USD customer returns 409 currency_migration_required, and the UI tells the member to email cristian@nan.builders. This notice must be removed when this flow ships.
  • Related: Verify USD→EUR premium migration on 2026-10-04 (gautierdr@gmail.com) #88 (verification of a manual USD→EUR premium migration).

Migration model

  1. Create a new EUR subscription via Stripe Checkout. The member has to confirm their card (a new PaymentMethod/mandate in EUR).
  2. Cancel the USD subscription only after the EUR one is paid (webhook-confirmed), never before.
  3. No access gap: entitlement must stay continuous across the switch (membership and any slot).
  4. Pricing: $75 vs €70 can be a price increase depending on FX. The comms have to be honest about it, and we need a decision on the proration/credit story.

Acceptance criteria

  • Self-serve flow in cloud-ui: a USD member who wants a workspace (or just wants EUR) can migrate without emailing support.
  • Combined checkout: membership (EUR) and slot (EUR) in one Checkout Session, so migrating and buying a workspace is a single step.
  • USD subscription cancelled only after the EUR invoice is paid; idempotent and safe on webhook retries/out-of-order events. Tested for failure paths (EUR payment fails, member abandons checkout, so the USD sub stays untouched).
  • No entitlement gap: tests assert the member is subscribed at every point of the switch.
  • Proration story defined and implemented (credit for unused USD period, or align the EUR start with the USD period end).
  • Comms: email template plus in-app notice explaining the change, the price in EUR, and the FX implication.
  • Remove the temporary 409 currency_migration_required "email cristian@nan.builders" notice, and make checkout go straight to the migration flow instead.
  • Runbook for support cases (partial failures, disputes during migration).

Notes

  • Never modify live Stripe configuration without explicit confirmation.
  • Per-customer Checkout Sessions only, never shared payment links.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions