-
Notifications
You must be signed in to change notification settings - Fork 534
Migration guide for v15
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 Python SDK specific changelog for v15 has the corresponding changes in the SDKs as well as SDK specific breaking changes.
Python versions 3.7 and 3.8 are no longer supported. The package now requires Python >= 3.9.
Action required: Upgrade to Python 3.9 or later before updating to the latest SDK version. For more information, see our language version support policy.
Note that Python 3.9 support will be dropped in March 2027. Please make plans to update to at least Python 3.10 before then.
TKTK
The v15 release of stripe-python introduces native Decimal 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 Python's decimal.Decimal instead of str in both request params and response objects. This applies to V1 and V2 resources.
The SDK handles conversion to/from the string wire format transparently.
If you read a decimal field from one Stripe object and pass it to another without manipulating it, no changes are needed.
Before:
invoice = stripe.Invoice.retrieve("in_xxx")
amount = invoice.lines.data[0].pricing.unit_amount_decimal # "9.99" (str)
parsed = float(amount)After:
invoice = stripe.Invoice.retrieve("in_xxx")
amount = invoice.lines.data[0].pricing.unit_amount_decimal # Decimal("9.99")
str(amount) # "9.99"
float(amount) # 9.99Before:
stripe.Price.create(
unit_amount_decimal="9.99",
currency="usd",
recurring={"interval": "month"},
product="prod_xxx",
)After:
from decimal import Decimal
stripe.Price.create(
unit_amount_decimal=Decimal("9.99"),
currency="usd",
recurring={"interval": "month"},
product="prod_xxx",
)Code that compares decimal field values using string equality will break:
# Before — worked
invoice.lines.data[0].pricing.unit_amount_decimal == "9.99" # True
# After — breaks (Decimal != str)
invoice.lines.data[0].pricing.unit_amount_decimal == "9.99" # False
# Fix — compare as Decimal
from decimal import Decimal
invoice.lines.data[0].pricing.unit_amount_decimal == Decimal("9.99") # TrueRequest param types are Decimal (not str). If you use type checking:
from decimal import Decimal
from stripe.params import PriceCreateParams
params: PriceCreateParams = {
"unit_amount_decimal": Decimal("9.99"), # Decimal, not str
"currency": "usd",
"recurring": {"interval": "month"},
"product": "prod_xxx",
}Every field below changes from str to Decimal on both response objects and request params.
Billing
| Resource | Field |
|---|---|
stripe.Plan |
amount_decimal |
stripe.Plan |
tiers[].flat_amount_decimal |
stripe.Plan |
tiers[].unit_amount_decimal |
stripe.Price |
unit_amount_decimal |
stripe.Price |
tiers[].flat_amount_decimal |
stripe.Price |
tiers[].unit_amount_decimal |
stripe.Price |
currency_options[].unit_amount_decimal |
stripe.Price |
currency_options[].tiers[].flat_amount_decimal |
stripe.Price |
currency_options[].tiers[].unit_amount_decimal |
stripe.InvoiceItem |
quantity_decimal |
stripe.InvoiceItem |
pricing.unit_amount_decimal |
stripe.InvoiceLineItem |
quantity_decimal |
stripe.InvoiceLineItem |
pricing.unit_amount_decimal |
stripe.CreditNoteLineItem |
unit_amount_decimal |
Climate
| Resource | Field |
|---|---|
stripe.climate.Order |
metric_tons |
stripe.climate.Product |
metric_tons_available |
Checkout
| Resource | Field |
|---|---|
stripe.checkout.Session |
currency_conversion.fx_rate |
Issuing
| Resource | Field |
|---|---|
stripe.issuing.Authorization |
fleet.reported_breakdown.fuel.gross_amount_decimal |
stripe.issuing.Authorization |
fleet.reported_breakdown.non_fuel.gross_amount_decimal |
stripe.issuing.Authorization |
fleet.reported_breakdown.tax.local_amount_decimal |
stripe.issuing.Authorization |
fleet.reported_breakdown.tax.national_amount_decimal |
stripe.issuing.Authorization |
fuel.quantity_decimal |
stripe.issuing.Authorization |
fuel.unit_cost_decimal |
stripe.issuing.Transaction |
purchase_details.fleet.reported_breakdown.fuel.gross_amount_decimal |
stripe.issuing.Transaction |
purchase_details.fleet.reported_breakdown.non_fuel.gross_amount_decimal |
stripe.issuing.Transaction |
purchase_details.fleet.reported_breakdown.tax.local_amount_decimal |
stripe.issuing.Transaction |
purchase_details.fleet.reported_breakdown.tax.national_amount_decimal |
stripe.issuing.Transaction |
purchase_details.fuel.quantity_decimal |
stripe.issuing.Transaction |
purchase_details.fuel.unit_cost_decimal |
V2
| Resource | Field |
|---|---|
stripe.v2.core.Account |
identity.individuals[].relationship.percent_ownership |
stripe.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).
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.
Resource amount fields now use the shared stripe.v2.Amount class instead of per-resource nested classes.
# Before
account = stripe.v2.core.AccountService.retrieve("acct_123")
amount = account.identity.business_details.annual_revenue.amount
# amount was typed as Account.Identity.BusinessDetails.AnnualRevenue.Amount
# After
from stripe.v2 import Amount
amount = account.identity.business_details.annual_revenue.amount
# amount is now typed as Amount
print(amount.value) # int
print(amount.currency) # str, e.g. "usd"If you were referencing the nested Amount class directly (e.g. in type annotations), update the import:
# Before
from stripe.v2.core._account import Account
def process(amt: Account.Identity.BusinessDetails.AnnualRevenue.Amount): ...
# After
from stripe.v2 import Amount
def process(amt: Amount): ...