Future-proofed payments: 6 ways to improve upgrading your Stripe integration
Tags: stripe, payments, webdev, productivity
Published: 2021-11-19 23:36:12


## Introduction

*If you’re getting paid and business is going well, it might be hard to justify the tradeoff between upgrading your Stripe integration and working on a new product or feature. Typically when we talk about upgrading we’re referring to the API version you’re on. These days upgrading could also mean replacing code with one or more of Stripe’s hosted products. Upgrading can help you take advantage of new functionality or to streamline responses so the API is faster for you. It can also help pay down tech debt and reduce complexity in the code you have to maintain.*

*In this post, we’ll look at how to prepare for upgrading your integration by building a strong foundation of [documentation](#how_to_start:_document_your_pay_flows), [error handling and logging](#pay_down_tech_debt) beforehand. We’ll look at [evaluating new low-code products](#evaluate_new_stripe_products_and_low-code_options), how to scope the [impact of an upgrade](#assess_an_api_upgrade).  Finally we'll [review tools](#stripe_tools_to_help_you_with _your_upgrade) Stripe offers to help you integrate and test, and [options to consider when you upgrade your API version](#strategies-savvy-developers-use-to-manage-stripe- api-version-updates).*

### How to start: Document your pay flows
Stripe supports a myriad of ways to accept payments and if you haven’t done so already, you should document your payment flows. This allows you to foresee the downstream impacts of upgrading your API version. To help you get started, answer these questions: 

- What do your payment flows look like? For example, do customers make one-time payments or are they billed automatically for subscriptions? Do you save customer information for future purchases? Do you support both in-person and online payments?  What payment methods can customers use? 
- What Stripe products are you using? For example you might be using [Checkout](https://stripe.com/docs/payments/checkout) or [Elements](https://stripe.com/docs/payments/elements) to accept payments online. You might also be using [Billing](https://stripe.com/docs/billing) to manage recurring revenue, or [Terminal](https://stripe.com/docs/terminal) for in-person payments. Keeping track of the payment products you use brings clarity to your payment flows.
- What API endpoints do you call? Clearly delineate how these calls are used for different functionality within your integration. Are they used for payments flows, customer onboarding, or as part of your notification and event handling? Understanding how you use different endpoints can help you approach an upgrade incrementally. 
- Document how data returned from the API or from webhooks is stored and subsequently used.  What teams rely on this data? Does the finance team use this data to close their books? Are there additional changes required in other services? 
- What Stripe SDKs are you using and which versions? What’s the full chain of dependencies running on your systems?
- As you document your flows and how you use the API, you can also check your test suite and confirm you have robust test coverage. 

As an example, let’s take a look at the payment flows for an imaginary business, a yoga studio located in the US.  This studio has been a Stripe user for many years and sells both monthly memberships as well as online video purchases.  They’re in the process of integrating with [Terminal](https://stripe.com/docs/terminal) for their in-person purchases.  They haven’t touched their subscription or online payments integrations in years but now that they are working on a new Terminal integration, they’re wondering if they should upgrade their other flows.  Here’s a high level overview of their integration that outlines the three ways they accept payments, the API resources they use, and object types they receive webhook events for. 

![Example Pay Flows Diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztrb3zwqr02u7pju6tbr.png)

***

### Evaluate new Stripe products and low-code options
After you understand your payment flows and business requirements, it’s worth evaluating whether you could reduce the complexity of your code base by migrating to one of Stripe’s hosted products such as [Checkout](https://stripe.com/docs/payments/checkout) or the [customer portal](https://stripe.com/docs/billing/subscriptions/customer-portal).  Migrating to a hosted product may reduce the size of your code base and help future-proof your integration. You’ll also get to take advantage of new functionality as it’s added with minimal or no additional development. 

Consider some of these Stripe updates from the last few years. They introduced both new APIs and products, which added more integration options for users: 

- **Online Payments:** In 2019 we introduced the [Payment Intents API](https://stripe.com/docs/payments/payment-intents) which was an improved, forward-looking abstraction compared to our previous disparate payment APIs, such as [Charges, Tokens, and Sources](https://stripe.com/docs/payments/older-apis). More recently we’ve released the [Payment Element](https://stripe.com/docs/payments/payment-element), a Javascript component that supports accepting multiple payment types instead of having to create a separate Element for each payment method. Along the way we also rolled out low and no-code options for integrating payments, which included [Stripe Checkout](https://stripe.com/docs/payments/checkout), [Payment Links](https://stripe.com/docs/payments/payment-links), and [Invoices](https://stripe.com/docs/invoicing/dashboard).  
- **Tax handling:** Developers asked for better tax support for years. Starting with the [August 27th 2020 API upgrade](https://stripe.com/docs/upgrades#2020-08-27), we introduced the [Tax Rates API](https://stripe.com/docs/upgrades#2020-08-27) to help better model taxes. More recently, we rolled out [Stripe Tax](https://stripe.com/docs/tax) which allows Stripe to manage more of the complexity around tax obligations. If you collect taxes, you know how cumbersome the process can be and if you aren’t using either of these solutions right now, it’s worth evaluating them.  
- **Connect account onboarding**: Throughout 2019 we introduced [significant improvements](https://stripe.com/docs/upgrades#2019-02-19) to the Accounts API to improve onboarding of custom accounts.  We also released [Connect Onboarding](https://stripe.com/docs/connect/connect-onboarding), a Stripe-hosted identity verification product that platforms can use instead of building their own onboarding flow.   

To assess whether a low-code product would work for you, we recommend comparing the [features and functionality](https://stripe.com/docs/payments/online-payments#compare-features-and-availability) of different products with building a custom integration. You should also think about what you might need for future growth or expansion. Returning to our yoga studio example, let’s say they want to sell to customers outside of the US, and would like to to accept more payment methods like mobile wallets.  To broaden their customer base and payment method support, they would need to migrate from their older integration (that only accepts cards) to a [newer one utilizing the Payment Intent API](https://stripe.com/docs/payments/older-apis#comparing-the-apis). There are a few upgrade paths they could take: 

- The first option they should evaluate would be to replace their Elements integration with Checkout for both their [video purchases](https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=checkout) and [subscriptions](https://stripe.com/docs/billing/quickstart). This would eliminate code they have to maintain and they would get new features like localization in more languages, more (payment method types)[https://stripe.com/docs/payments/dashboard-payment-methods], (promotion codes)[https://stripe.com/docs/payments/checkout/discounts] and (upsells)[https://stripe.com/docs/payments/checkout/upsells] with little to no development work. 
- They could also integrate with the [customer portal](https://stripe.com/docs/billing/subscriptions/integrating-customer-portal) which would eliminate existing code for managing customer subscriptions and storing payment methods. 
- Lastly if they wanted to stay with a fully customized integration without using hosted products, they could migrate from Charges and Tokens to [Payment Intents and the Payment Element](https://stripe.com/docs/payments/accept-a-payment?platform=web&ui=elements). They wouldn’t necessarily reduce their code base with this update but it would enable them to accept more payment methods, and they’d be using the same APIs with Terminal. 

***

### Assess an API upgrade
To scope the changes required for an API upgrade, you’ll need to review the breaking changes listed in the version [API changelogs](https://stripe.com/docs/upgrades#api-changelog) identify changes relevant to your integration. We also recommend you review the changelog for the client library you are using. Here's an example from our (Ruby library)[https://github.com/stripe/stripe-ruby/blob/master/CHANGELOG.md]. The client library changelog will list nonbreaking new functionality you may want to use.

For example, let’s look at the [August 27, 2020 changelog] (https://stripe.com/docs/upgrades#2020-08-27).  For each change listed, we’ll note the products and API resources that are affected by the change. Doing this helps us eliminate changes that we don’t need to worry about. 

| Affected Products | APIs |                               Description of change |
| ------ | ------- | ------- |                                                                                                                                                                                                                                        
| Billing   | [Tax Rates](https://stripe.com/docs/api/tax_rates) <br /> Billing APIs | We have removed `tax_percent` from objects and requests in favor of [tax rates](https://stripe.com/docs/api/tax_rates). |                                                                                                                                                                                                      
| Billing           | [Subscription Schedules](https://stripe.com/docs/api/subscription_schedules)                            | On subscription schedules, `phases.plans` has been renamed to `phases.items`. This applies for the [subscription schedule object](https://stripe.com/docs/api/subscription_schedules/object#subscription_schedule_object-phases) as well as [create](https://stripe.com/docs/api/subscription_schedules/create#create_subscription_schedule-phases) and [update](https://stripe.com/docs/api/subscription_schedules/update#update_subscription_schedule-phases) requests.|                                                                                                                 
| various           | [Payment Methods](https://stripe.com/docs/api/payment_methods)                                   | Deprecate the `payment_method.card_automatically_updated` webhook in favor of `payment_method.automatically_updated`. |                                                                                                                                                 
| Checkout          | [Checkout Sessions](https://stripe.com/docs/api/checkout/sessions)                                | Checkout Sessions no longer include the `display_items` property. Use the includable `line_items` property instead. |                                                                                                                                                             
| Connect           | [Accounts](https://stripe.com/docs/api/accounts) <br /> [Capabilities](https://stripe.com/docs/api/capabilities) <br /> [Country Specs](https://stripe.com/docs/api/country_specs)  | The `requirements` hash on the Account and Capability objects, and the `verification_fields` hash on the Country Spec object have newly formatted strings for requirements that are related to key persons associated with an account. ... (additional details in sub bullets trimmed) |
| Connect           | [Accounts](https://stripe.com/docs/api/accounts) <br /> [Persons] (https://stripe.com/docs/api/persons) <br /> [Capabilities] (https://stripe.com/docs/api/capabilities) | In the Accounts/Persons/Capabilities API, several new error codes have been introduced in the `requirements.errors` array. See [Account requirements errors](https://stripe.com/docs/api/accounts/object#account_object-requirements-errors) for more information. These error codes are ...(additional details trimmed)|
| Payments           | [Payment Methods](https://stripe.com/docs/api/payment_methods)                                     | The `payment_method_details.card.three_d_secure` fields on the Charge object have been updated. The `succeeded` and `authenticated` booleans have been removed; please use the `result` enum instead. |                                                                                  
| Subscriptions           | [Customers](https://stripe.com/docs/api/customers) | The `subscriptions` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |                                                                                                 
| Billing           | [Plans](https://stripe.com/docs/api/plans)                                             | The `tiers` property on Plan is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed |                                                                                                                   
| varies            | [Customers](https://stripe.com/docs/api/customers)                                        | The `sources` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |                                                                                                           
| varies            | [Customers](https://stripe.com/docs/api/customers)                                        | The `tax_ids` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |                                                                                                           
| Billing           | [Subscriptions](https://stripe.com/docs/api/subscriptions)                        | The `prorate` and `subscription_prorate` parameters are deprecated in favor of `proration_behavior`. |                                                                                                                                                                                                    


After reviewing the changes, we can see they fall into five categories: 

- **Billing APIs** (5 items): Subscriptions, Plans as well as other APIs that had a `tax_percent` attribute such as Invoice Items. 
- **Connect APIs** (2 items):  Accounts, Persons, Country Specs
- **Customers** (3 items): Customers 
- **Payment methods** (2 items) 
- **Checkout** (1 item) 

We can take this list, compare it to our payment flows and endpoint inventory, and eliminate several changes that aren’t relevant to our integration. For example, the yoga studio doesn’t use Connect, Checkout or the `three_d_secure` field on the Payment Method so none of those changes impact our integration. It also doesn't Subscription Schedules. This leaves the other changes that affect Billing and the Customer object.  At this point, we’d look more closely at our code and our business needs to see which changes affect existing code, and if there’s anything new (such as Tax Rates) to add to the integration.

| Affected Products | Affected APIs                                     | Description of change |                                                                                                                                                   
| ------ | ------- | ------- |     
| Billing  | [Tax Rates](https://stripe.com/docs/api/tax_rates)  <br /> Billing APIs | We have removed `tax_percent` from objects and requests in favor of [tax rates](https://stripe.com/docs/api/tax_rates). |                                                                                           
| Subscriptions           | [Customers](https://stripe.com/docs/api/customers) | The `subscriptions` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |             
| Billing           | [Plans](https://stripe.com/docs/api/plans)                                             | The `tiers` property on Plan is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed |                                                                                                                   
| varies            | [Customers](https://stripe.com/docs/api/customers)                                        | The `sources` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |                                                                                                           
| varies            | [Customers](https://stripe.com/docs/api/customers)                                        | The `tax_ids` property on Customers is no longer included by default. You can [expand the list](https://stripe.com/docs/api/expanding_objects) but for performance reasons we recommended against doing so unless needed. |                                                                                                           
| Billing           | [Subscriptions](https://stripe.com/docs/api/subscriptions)                        | The `prorate` and `subscription_prorate` parameters are deprecated in favor of `proration_behavior`. |                                                                                


To understand the scope of a particular change, make sure you understand what *type* of change it is.  Did the structure of a response or resource *change*? Did the parameters of an API call change?  

For example, let’s take a look at the three changes that affected the Customers API.  They all changed the structure of a resource. The `sources`, `tax_ids`, and `subscriptions` properties were all removed from the Customer object, but there were no changes to how Customer endpoints are called. Incorporating these changes would be limited to modifying code that expected those attributes in the response of an API call. If you still needed those attributes, you could make other calls or use the (expand)[https://stripe.com/docs/api/expanding_objects] parameter. 

In the Subscription API change, the `prorate` attribute was replaced with `proration_behavior`. This is a good example of how both an API call and the underlying resource were changed. If you were using this attribute, you’d need to potentially modify code that accesses the attribute, and update Create and Update API calls.

When Stripe releases new API versions, we recommend you take the time to scope incorporating those changes into your integration, and make a conscious decision about whether to upgrade now or let the changes accumulate over time. See [Strategies savvy developers use to manage Stripe API version updates](#strategies-savvy-developers-use-to-manage-stripe- api-version-updates) for suggestions on how to manage version changes. 

***

### Pay down tech debt
Similar to how documenting your payment flows can help ensure you are properly scoping changes, strong foundations in error handling, monitoring, and testing make it easier to understand the impact of an update and increase the confidence you have in making changes.  Before you start modifying your code, here are some areas to review: 

1. Verify you’re handling and logging errors correctly, both on the server and client-side. This is a good time to check what you show to customers when an error occurs.  Client-side errors returned from Elements, Checkout, or our mobile SDKs are intended to be shared with your customers. Server-side errors returned from the API generally identify integration errors and aren’t usually helpful for your customers to see.    
2. Make sure your code alerts you when it receives unknown data and isn’t silently failing.  For example, as you modify your integration you may receive [errors code](https://stripe.com/docs/error-codes) or [event types](https://stripe.com/docs/api/events/types) you haven’t handled before. Flagging these can help you identify spots in your integration that need to be updated.  Many server-side errors include a human readable [message](https://stripe.com/docs/api/errors#errors-message). Logging these messages can help you pinpoint integration issues. 
3. Another piece of code to review is your [webhook handling](https://stripe.com/docs/webhooks/best-practices#event-handling).  Ensure that your webhook endpoints can handle delayed or duplicate notifications and don’t require notifications to occur in a specific order.  Also, review the event types your endpoints are receiving and remove the ones you don't need for your integration as those can cause unnecessary load on your system. 
4. Lastly confirm you are taking advantage of our [idempotency support](https://stripe.com/docs/idempotency).  Idempotent keys should be used for all POST requests to the Stripe API; most official client libraries send them automatically as long as they’re configured to send retries.

***

### Strategies savvy developers use to manage Stripe API version updates

There is a lot of flexibility built into Stripe’s API versioning which can help you [control your upgrade](https://stripe.com/docs/upgrades) and make changes incrementally. We recommend you start with your API calls and webhook handling and upgrade your Account API version as the final step. 

If you’re using one of our dynamically typed libraries, you can control the API version on a per call basis by passing the [Stripe Version header](https://stripe.com/docs/api/versioning).  Using this header is recommended when you upgrade, as it allows you to isolate the calls you’re changing. 

If you’re using one of Stripe’s statically typed libraries, such as [stripe-java](https://github.com/stripe/stripe-java), [stripe-go](https://github.com/stripe/stripe-go), or [stripe-dotnet](https://github.com/stripe/stripe-dotnet), the library version determines the API version for used in your calls. You can find out what API version a particular library is using by reviewing the library’s [changelog](https://github.com/stripe/stripe-dotnet/blob/master/CHANGELOG.md#3912---2020-09-01). 

When you upgrade an API call to use a new API version, your webhook event payloads triggered by that call continue to be constructed using the API version on your account.  This means that the structure of the object returned in an event may differ from the structure from the API call. Let’s use an example from the changes we looked at above, in this case the changes in the `2020-08-27` API version that removed the attributes for `sources`, ‘tax_ids`, or `subscriptions` from the Customer object.  If your account was on an API version prior to  `2020-08-27` and you made a call to create a customer using the Stripe Version header of `2020-08-27` you wouldn't see these attributes in the response.  However, the customer object in the `customer.created` event would still include those attributes since you hadn’t upgraded your account.

![Comparison on customer object returned in different API versions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eyv1lbcmvqo8gbr5suho.png)

Event objects will include the [API version](https://stripe.com/docs/api/events/object#event_object-api_version) that was used to generate the data, either Dashboard's API version or the version set specifically on the endpoint.  To upgrade your webhook handlers, [we recommend setting up a second endpoint](https://stripe.com/docs/upgrades#how-can-i-upgrade-my-api) with the API version set to the newer version.  This way you’ll receive both the old and new versions of the objects and can work on your upgrade without breaking your existing event handling. ​​If your webhook handler is failing and returning 4XX or 5XX http status code responses to Stripe during the transition, Stripe will [retry delivery of those webhook notifications](https://stripe.com/docs/webhooks#built-in-retries). 

You can create endpoints configured to a specific API version through the [API](https://stripe.com/docs/api/webhook_endpoints/create#create_webhook_endpoint-api_version) or through the [Dashboard](https://dashboard.stripe.com/test/webhooks/create). Note that you’ll only see the option to set the API version on the endpoint if your account is set to an older API version. 

![Stripe Dashboard Webhoook Endpoint Configuration Page](https://lh4.googleusercontent.com/AWw4H1rKlGPYVTAbdpxha68GDlfgUdBzH7-sqvkD2ElGpY9xO50gGnL0LkvYHFf5qEOPL0obSh1jrZC86lkmKqA3HRqxAJgA8GcgYlva5GVvT0CU0PKNwIsu5mqJTnJ-H9oPYkWN)

Your account version affects the structure of objects received with [Stripe.js](https://stripe.com/docs/payments/elements) methods such as [confirmCardPayment](https://stripe.com/docs/js#stripe-confirm-card-payment). That means that if you’re using Stripe.js as part of an Elements integration you’ll need to handle any changes listed in the changelog before you upgrade your account. 

Your account’s default API version also affects Automated Billing operations performed by Stripe (e.g., generating an invoice for a new subscription period). Again, you’ll want to check the API changelog for details about how your default API version impacts these operations.

If upgrading to the newest version is overwhelming, you can update to an intermediate version instead. That way you can still use some of the improvements. While you can’t make that change yourself through the Dashboard, you can contact Stripe support for help.    

After you’ve upgraded the API version on your account, there’s a 72 hour window during which you can [roll it back](https://stripe.com/docs/upgrades#rolling-back-your-api-version) through the Dashboard. If you discover an unexpected issue after upgrading, you can roll back to your original version while you make your fixes. 

***

### Stripe tools to help you with your upgrade
Stripe offers a variety of tools to help you upgrade and test your integration:  

- You’re probably familiar with test mode in your Stripe account, but you can also set up a separate Stripe account to use for testing. This can be helpful when you want to test the effect of setting the API version of your account.  
- The [Stripe CLI](https://stripe.com/docs/cli) is an invaluable resource for understanding the Stripe API, and there are a couple features that are particularly useful when working on an upgrade:
    - [Resource commands](https://stripe.com/docs/cli/resources) like `stripe customers create` support passing a specific API version through a  `-v` or `--stripe-version` flag.  These commands are a great way to quickly test out a call. 
    - As you are upgrading your webhook endpoints, you can use the CLI to [trigger an event](https://stripe.com/docs/cli/trigger) to test your new webhook handlers.  
    - Use [fixtures](https://stripe.com/docs/cli/fixtures) to test a series of API tests or create test mode data in your account.
- [Stripe for Visual Studio Code](https://stripe.com/docs/stripe-vscode) integrates with the Stripe CLI and provides additional features such as code snippets and a linter.  
- Take advantage of Stripe’s test cards and payment methods. You probably know the classic `4242 4242 4242 4242` test card number, but there is a whole set of numbers that return [specific responses](https://stripe.com/docs/testing#cards-responses) such as failed verification checks for addresses and codes. Other payment methods have similar test credentials for you to use, and Connect has [additional resources](https://stripe.com/docs/connect/testing) for testing account onboarding, identity verification, and payouts.  
- [The Stripe developer dashboard](https://dashboard.stripe.com/developers) gives you an overview of your integration and can help you flag failed API requests and confirm events are reaching your webhooks as expected. The dashboard also shows you your current API version and lists the changelog items for new versions.

***

### Final notes
Hopefully this article makes the prospect of upgrading a little less scary and may even get you excited about new functionality.  We’re constantly updating our API and products as a result of feedback from developers - we want to hear from you. Reach out on [Twitter](https://twitter.com/StripeDev), [Discord](https://discord.com/invite/RuJnSBXrQn) or by [email](mailto:support@stripe.com).  Find us on [YouTube](https://www.youtube.com/stripedevelopers), and be sure to subscribe to our monthly [developer digest](https://go.stripe.global/dev-digest). 

Thanks to [CJ Avilla](https://dev.to/cjav_dev), [Dan Cobb]( https://www.linkedin.com/in/dcobb15/), [Carol Huang](https://dev.to/carol), [Brody Klapko](https://www.linkedin.com/in/brodyklapko/), and [Bernerd Schaefer]( https://linkedin.com/in/bernerdschaefer) for their suggestions for this post, and to [Chris Traganos](https://dev.to/trag) for making the visuals!