@todesktop/shared
v7.188.81
Published
Most of the code for coordinating Stripe subscriptions can be found in `plans.ts`. Conceptually, we organize subscriptions as follows:
Downloads
2,187
Readme
Stripe Subscriptions
Most of the code for coordinating Stripe subscriptions can be found in plans.ts
. Conceptually, we organize subscriptions as follows:
- A
Price
captures the ID information of a Stripe Price and it's current status:inactive
means that the price should no longer be used (but may have been used previously).active
means that the price should be used going forward.
- A
Product
maps to what is shown in Stripe's Product Catalogue UI. These help use organize the dev and prod versions of aProduct
, as well as their underlyingproductId
andpriceIds
. - A
Plan
is a collection ofProduct
s, organized by their tier (basic, legacy_pro, pro, scale).
Each Plan also specifies the eligiblePlanTiers
that it accepts for validation purposes. E.g. the basic plan specifies ['basic', 'legacy_pro', 'pro', 'scale']
in its eligiblePlanTiers
field, meaning that Products belonging within any of those tiers would satisfy validation requirements. Similarly, the basic plan specifies ['scale']
in its tiers field, meaning that only Products belonging to the scale Plans would satisfy validation.
Adding a new subscription price
Before adding a new price, you'll first need to identify the Stripe Stripe Product that the price should be added to.
Once you've added a new price to the product in Stripe's live
and test
mode, then you can come back and add it to the relevant product in plans.ts
.
For example, these are the dev and prod records for the legacy enterprise product:
const legacyEnterpriseDev = createProduct('prod_Hc9PMnHUmHvOlw', {
monthly_700: createPrice('price_1H2v6JIewCKA2h0IgUwsuctb', 'active'),
});
const legacyEnterpriseProd = createProduct('prod_GuGGWeMQ3SCuE9', {
monthly_700: createPrice('plan_GuGICX6nRtDthN', 'active'),
});
If you added a new Stripe price to this product that is billed yearly for $10,000, then you would add update the products as follows:
const legacyEnterpriseDev = createProduct('prod_Hc9PMnHUmHvOlw', {
monthly_700: createPrice('price_1H2v6JIewCKA2h0IgUwsuctb', 'active'),
yearly_10000: createPrice('...', 'active'),
});
const legacyEnterpriseProd = createProduct('prod_GuGGWeMQ3SCuE9', {
monthly_700: createPrice('plan_GuGICX6nRtDthN', 'active'),
yearly_10000: createPrice('...', 'active'),
});
Rebuilding the Stripe Customer Portals
ToDesktop's subscription flow needs to support both CLI and ToDesktop Builder customers. To achieve this, we dynamically create/load billing portals based on whether the customer is a CLI or ToDesktop Builder user, whether the customer needs to Upgrade or Update their plan, and whether the environment is in prod or dev.
This leaves us with 8 unique customer portal configurations:
- cliUpdateConfigurationDev
- cliUpdateConfigurationProd
- cliUpgradeConfigurationDev
- cliUpgradeConfigurationProd
- builderUpdateConfigurationDev
- builderUpdateConfigurationProd
- builderUpgradeConfigurationDev
- builderUpgradeConfigurationProd
Each configuration specifies the products and prices (with an active
status) that should be displayed when a user navigates to the customer billing portal.
The web app and desktop app then only need to specify the PortalConfigKey
when creating a checkout session from the client:
// begin a CLI upgrade customer portal session
await createCustomerPortalSession({
configuration: PortalConfigKey.CLIUpgradeProd,
flowData: {
type: 'subscription_update',
subscription_update: { subscription: subscription.id },
},
});
If you have updated the products that are used by any of the portal configurations, then you'll also need to increase the PORTAL_VERSION
constant by 1. This will ensure that the portals are rebuilt to use the latest products and prices. This happens in createCustomerPortalSession
in the web app.