-
Notifications
You must be signed in to change notification settings - Fork 532
Migration guide for v85
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 Go SDK specific changelog for v85 has the corresponding changes in the SDKs as well as SDK specific breaking changes.
Go versions 1.20 and 1.21 are no longer supported. The package now requires Go >= 1.22.
Action required: Upgrade to Go 1.22 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 Go 1.22 and 1.23. Please make plans to update to at least Go 1.24 (and ideally Go 1.25 or higher) before September 2026.
List and Search methods on stripe.Client services have changed their return type. Previously, they returned stripe.Seq2[*T, error] directly â a bare iterator you could range over. Now they return a *V1List[*T]/*V2List[*T] struct. To iterate, call .All(ctx) on the returned struct.
This change enables accessing LastResponse and other properties (e.g. the raw HTTP response, etc.), which was not possible with the previous design.
If you only auto-paginate (the common case), the fix is adding .All(ctx) to your range expression:
// Before
for customer, err := range client.V1Customers.List(ctx, params) {
if err != nil {
return err
}
fmt.Println(customer.ID)
}
// After
for customer, err := range client.V1Customers.List(ctx, params).All(ctx) {
if err != nil {
return err
}
fmt.Println(customer.ID)
}The same applies to the callback-style iteration pattern on older Go versions:
// Before
client.V1Customers.List(ctx, params)(func(customer *stripe.Customer, err error) bool {
// handle customer
return true
})
// After
client.V1Customers.List(ctx, params).All(ctx)(func(customer *stripe.Customer, err error) bool {
// handle customer
return true
})Search methods return *V1SearchList[*T], but follow the same pattern. Append .All(ctx) to get the iterator:
// Before
for customer, err := range client.V1Customers.Search(ctx, params) { ... }
// After
for customer, err := range client.V1Customers.Search(ctx, params).All(ctx) { ... }The V1List/V2List structs expose per-page data that was previously inaccessible:
list := client.V1Customers.List(ctx, params)
data := list.Data() // []*stripe.Customer for the current page
meta := list.Meta() // stripe.ListMeta â includes HasMore
err := list.Err() // error from fetching the current page
resp := list.LastResponse() // *stripe.APIResponse with RawJSONThe package-level client.API pattern (e.g., customer.List(params) with .Next()) is unchanged. This change only affects methods on stripe.Client services.
stripe-go v85 adds a new UnsetFields mechanism for explicitly clearing scalar fields on params structs. This works for both V1 and V2 API requests.
Each params struct that has clearable fields now gets:
- A typed
UnsetFieldsslice - Named constants for each clearable field
- An
AddUnsetField()method
For V1 requests, this sends field= (empty string) in the form body to clear the field. For V2 requests, this sends "field": null in the JSON body.
Previously, there was no mechanism for clearing fields in V2, and for V1 you had to use params.AddExtra("field_name", "").
Before:
params := &stripe.SubscriptionUpdateParams{}
params.AddExtra("pause_collection", "")After:
params := &stripe.SubscriptionUpdateParams{}
params.AddUnsetField(stripe.SubscriptionUpdateParamsUnsetFieldPauseCollection)Map fields whose values can be cleared individually now use pointer value types. This enables setting a map entry to nil to clear it. Previously, string-valued maps could clear individual entries by setting them to "", but there was no way to clear an int64 map entry.
params := &stripe.BalanceSettingsUpdateParams{
Payments: &stripe.BalanceSettingsUpdatePaymentsParams{
Payouts: &stripe.BalanceSettingsUpdatePaymentsPayoutsParams{
MinimumBalanceByCurrency: map[string]*int64{
"usd": stripe.Int64(5000),
// To clear a currency's minimum balance:
"eur": nil
},
},
},
}V2 API fields with format: decimal (such as percent_ownership on Account relationships) previously generated as *string. They now generate as *float64 with string-encoding struct tags â the wire format remains a JSON string, but Go code works with native float values.
Before:
pct := "75.25"
params := &stripe.V2CoreAccountCreateParams{
Identity: &stripe.V2CoreAccountCreateIdentityParams{
Individual: &stripe.V2CoreAccountCreateIdentityIndividualParams{
Relationship: &stripe.V2CoreAccountCreateIdentityIndividualRelationshipParams{
PercentOwnership: &pct, // was *string
},
},
},
}After:
pct := 75.25
params := &stripe.V2CoreAccountCreateParams{
Identity: &stripe.V2CoreAccountCreateIdentityParams{
Individual: &stripe.V2CoreAccountCreateIdentityIndividualParams{
Relationship: &stripe.V2CoreAccountCreateIdentityIndividualRelationshipParams{
PercentOwnership: &pct, // now *float64
},
},
},
}You can also use stripe.Float64(75.25) (or new(75.25) on Go 1.26+) as a shorthand.
V1 decimal fields already used float64 â only V2 fields are affected:
| Struct | Field |
|---|---|
V2CoreAccountIdentityIndividualRelationship |
PercentOwnership |
V2CoreAccountPersonRelationship |
PercentOwnership |
| All corresponding create, update, and token param structs for Account and Person relationships |
Before:
pctStr := *account.Identity.Individual.Relationship.PercentOwnership // string
pct, _ := strconv.ParseFloat(pctStr, 64)After:
pct := account.Identity.Individual.Relationship.PercentOwnership // float64
fmt.Println(pct) // 75.25V2 resources previously generated a separate, per-field Amount class for every monetary amount property (e.g., V2OutboundPaymentAmount, V2AnnualRevenueAmount, etc.). 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
// amount was *stripe.V2CoreAccountIdentityBusinessDetailsAnnualRevenue
Amount
amount := account.Identity.BusinessDetails.AnnualRevenue.Amount
fmt.Println(amount.Value) // int64
fmt.Println(amount.Currency) // stripe.Currency
// After
// amount is now *stripe.Amount
amount := account.Identity.BusinessDetails.AnnualRevenue.Amount
fmt.Println(amount.Value) // int64
fmt.Println(amount.Currency) // stripe.CurrencyIf you were referencing the type directly:
// Before
var amt *stripe.V2CoreAccountIdentityBusinessDetailsAnnualRevenueAmount
// After
var amt *stripe.Amount