Stripe | Financial Infrastructure to Grow Your Revenue

Stripe | Financial Infrastructure to Grow Your Revenue

4466 articles

Checkout Sessions have lower latency and new update semantics


Breaking changes

Checkout Sessions have lower latency and new update semantics Breaking changes

What’s new

This version offers improved latency on all Checkout Session APIs for subscription-mode Sessions, including when your customer confirms the Session.

It also fixes a bug with earlier versions that prevents your customers from updating a Session after the first payment attempt, such as not being able to update a billing address. They can now unblock themselves instead of refreshing.

Why is this a breaking change?

Because this change creates the subscription after the user has completed the payment, payment_intent doesn’t reference an invoice until the Checkout Session fully completes. This means the checkout.session.status property must be complete before the invoice is created.

If your integration currently relies on an invoice during the payment intent webhooks, we recommend that you update your integration to use the checkout_session.completed webhook instead, which ensures an invoice is present.

Impact

  • Subscriptions are now created after the user completes payment.
  • Failed payment attempts no longer result in an incomplete subscription with a finalized invoice.
  • An invoice isn’t present until the Checkout Session is in the complete state.

Select a language

Ruby

Python

PHP

Java

Node.js

Go

.NET

No results

require 'json'
require 'stripe'

# Don't put any keys in code. See https://docs.stripe.com/keys-best-practices.
# Find your keys at https://dashboard.stripe.com/apikeys.
client = Stripe::StripeClient.new('sk_test_BQokikJOvBiI2HlWgH4olfQ2')

# Using Sinatra
post '/webhook' do
 payload = request.body.read
 event = nil

 begin
 event = Stripe::Event.construct_from(
 JSON.parse(payload, symbolize_names: true)
 )
 rescue JSON::ParserError => e
 # Invalid payload
 status 400
 return
 end

 # Handle the event
 case event.type
 when 'payment_intent.succeeded'
 payment_intent = event.data.object # contains a Stripe::PaymentIntent
 # The subscription and invoice might not have been created at this stage.
 # Then define and call a method to handle the successful payment intent.
 # handle_payment_intent_succeeded(payment_intent)
 when 'checkout_session.completed'
 checkout_session = event.data.object # contains a Stripe::CheckoutSession
 # checkout_session.payment_intent is a string here,
 # but you can use this payment_intent token to fetch the associated invoice payment
 # through the /v1/invoice_payments API method and its guaranteed associated invoice
 # and invoice payment are non-null at this stage.
 # Then define and call a method to handle the successful completion of a Checkout Session
 # handle_checkout_session_completed(checkout_session)
 # ... handle other event types
 else
 puts "Unhandled event type: #{event.type}"
 end

 status 200
end

Upgrade

  1. View your current API version in Workbench.
  2. If you use an SDK, upgrade to the corresponding SDK version for this API version.
  • If you don’t use an SDK, update your API requests to include Stripe-Version: 2025-03-31. basil
  1. Upgrade the API version used for webhook endpoints .
  2. Test your integration against the new version.
  3. If you use Connect, test your Connect integration .
  4. In Workbench, perform the upgrade . You can roll back the version for 72 hours.

Learn more about Stripe API upgrades.

Last verified 2026-09-24

Is this helpful?