Skip to content

Migration guide for v21

Prathmesh Ranaut edited this page Apr 1, 2026 · 2 revisions

This version uses API version 2026-03-25.dahlia. If the format of this API version looks new to you, see our new API release process.

Please review our API changelog for 2026-03-25.dahlia to understand all the breaking changes to the Stripe API, the reasons behind them and potential alternatives.

The Node SDK specific changelog for v21 has the corresponding changes in the SDKs as well as SDK specific breaking changes.

Minimum Node version raised to 18

Node.js versions lower than 18 are no longer supported. The package now requires Node >= 18.

Action required: Upgrade to Node 18 or later before updating to the latest SDK version. For more information, see our language version support policy.

Note that this is the last major release that supports Node 18. Please make plans to update to at least Node 20 (and ideally Node 22 or higher) before September 2026.

Decimal fields use Stripe.Decimal instead of string

The v21 release of stripe-node introduces native decimal type support for all decimal_string fields. All fields with format: decimal in the Stripe API (such as unit_amount_decimal, quantity_decimal, and fx_rate) now use Stripe.Decimal instead of string in both request parameters and response objects. This applies to V1 and V2 resources.

Stripe.Decimal is a vendored arbitrary-precision decimal type backed by BigInt. It has zero external dependencies.

No changes needed if you only pass values through

If you read a decimal field from one Stripe object and pass it to another without manipulating it, no changes are needed — the Decimal value flows through transparently.

Reading decimal fields

Before:

const session = await stripe.checkout.sessions.retrieve('cs_test_xxx');
const rate: string = session.currency_conversion.fx_rate;
const parsed = parseFloat(rate);

After:

const session = await stripe.checkout.sessions.retrieve('cs_test_xxx');
const rate: Stripe.Decimal = session.currency_conversion.fx_rate;

// Convert to string
const rateStr: string = rate.toString();

// Convert to number (may lose precision for very large/small values)
const rateNum: number = rate.toNumber();

Setting decimal params

Before:

const price = await stripe.prices.create({
  unit_amount_decimal: '9.99',
  currency: 'usd',
  recurring: { interval: 'month' },
  product: 'prod_xxx',
});

After (CommonJS / TypeScript with esModuleInterop):

import Stripe from 'stripe';

const price = await stripe.prices.create({
  unit_amount_decimal: Stripe.Decimal.from('9.99'),
  currency: 'usd',
  recurring: { interval: 'month' },
  product: 'prod_xxx',
});

After (ESM):

import Stripe, { Decimal } from 'stripe';

const price = await stripe.prices.create({
  unit_amount_decimal: Decimal.from('9.99'),
  currency: 'usd',
  recurring: { interval: 'month' },
  product: 'prod_xxx',
});

Arithmetic with Decimal

Stripe.Decimal provides instance methods for basic arithmetic. add(), sub(), and mul() each take a single argument. div() additionally requires a precision (number of decimal places) and a rounding direction:

const a = Stripe.Decimal.from('10.50');
const b = Stripe.Decimal.from('3.25');

const sum = a.add(b);                    // 13.75
const diff = a.sub(b);                   // 7.25
const product = a.mul(b);                // 34.125
const quotient = a.div(b, 6, 'half-up'); // 3.230769

Affected fields

Every field below changes from string to Stripe.Decimal on both response objects and request params.

Billing

Resource Field
Plan amount_decimal
Plan tiers[].flat_amount_decimal
Plan tiers[].unit_amount_decimal
Price unit_amount_decimal
Price tiers[].flat_amount_decimal
Price tiers[].unit_amount_decimal
Price currency_options[].unit_amount_decimal
Price currency_options[].tiers[].flat_amount_decimal
Price currency_options[].tiers[].unit_amount_decimal
InvoiceItem quantity_decimal
InvoiceItem pricing.unit_amount_decimal
InvoiceLineItem quantity_decimal
InvoiceLineItem pricing.unit_amount_decimal
CreditNoteLineItem unit_amount_decimal

Climate

Resource Field
Climate.Order metric_tons
Climate.Product metric_tons_available

Checkout

Resource Field
Checkout.Session currency_conversion.fx_rate

Issuing

Resource Field
Issuing.Authorization fleet.reported_breakdown.fuel.gross_amount_decimal
Issuing.Authorization fleet.reported_breakdown.non_fuel.gross_amount_decimal
Issuing.Authorization fleet.reported_breakdown.tax.local_amount_decimal
Issuing.Authorization fleet.reported_breakdown.tax.national_amount_decimal
Issuing.Authorization fuel.quantity_decimal
Issuing.Authorization fuel.unit_cost_decimal
Issuing.Transaction purchase_details.fleet.reported_breakdown.fuel.gross_amount_decimal
Issuing.Transaction purchase_details.fleet.reported_breakdown.non_fuel.gross_amount_decimal
Issuing.Transaction purchase_details.fleet.reported_breakdown.tax.local_amount_decimal
Issuing.Transaction purchase_details.fleet.reported_breakdown.tax.national_amount_decimal
Issuing.Transaction purchase_details.fuel.quantity_decimal
Issuing.Transaction purchase_details.fuel.unit_cost_decimal

V2

Resource Field
V2.Core.Account identity.individuals[].relationship.percent_ownership
V2.Core.AccountPerson relationship.percent_ownership

Request-only decimal fields also change (e.g., price_data.unit_amount_decimal on Subscription, SubscriptionItem, SubscriptionSchedule, Quote, PaymentLink, Invoice line creation params).

TypeScript target requirement

The Decimal type uses BigInt internally. If your code uses BigInt literals directly (e.g., passing 100n to Decimal.from()), your tsconfig.json must target ES2020 or later. If you only construct decimals from strings (Decimal.from('9.99')), no tsconfig.json change is needed.

V2 Amount type consolidation

V2 resources previously generated a separate, per-field Amount class for every monetary amount property (e.g., OutboundPayment.Amount, AnnualRevenue.Amount). These duplicates have been replaced with a single shared Amount type. The fields (value and currency) are identical — only the type name and import path changed:

// Before
const amount: Stripe.V2.Core.Account.Identity.BusinessDetails.AnnualRevenue.Amount =
  account.identity.business_details.annual_revenue.amount;

// After
const amount: Stripe.V2.Amount =
  account.identity.business_details.annual_revenue.amount;

console.log(amount.value);    // number
console.log(amount.currency); // string, e.g. "usd"

Clone this wiki locally