Pending updates

    Learn how to handle payment failures when updating subscriptions.

    Updating a subscription generates a new invoice when:

    • The subscription requires payment for the first time, such as the end of a trial period.
    • The billing period changes.
    • Changing the subscription causes a proration and proration_behavior=always_invoice.

    By default, updates are applied regardless of whether payment on the new invoice succeeds. If payment fails, rolling back the updates is a manual process. You need to create a new invoice, prorate items on the invoice, and then initiate payment again. However, with the pending updates feature, you can make changes to subscriptions only if payment succeeds on the new invoice.

    1 Update the subscription Server-side

    You can use pending updates with the update subscription, create subscription item, and update subscription item calls. When you make the update, set payment_behavior=pending_if_incomplete. The example below adds a new price to a subscription. Because proration_behavior=always_invoice, an invoice is created and payment is attempted when the update is made.

    curl https://api.stripe.com/v1/subscriptions/sub_49ty4767H20z6a \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d payment_behavior=pending_if_incomplete \ -d proration_behavior=always_invoice \ -d "items[0][id]"=si_09IkI4u3ZypJUk5onGUZpe8O \ -d "items[0][price]"=price_CBb6IXqvTLXp3f
    # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = Stripe::Subscription.retrieve('sub_49ty4767H20z6a') Stripe::Subscription.update( subscription.id, { payment_behavior: 'pending_if_incomplete', proration_behavior: 'always_invoice', items: [ { id: subscription.items.data[0].id, price: 'price_CBb6IXqvTLXp3f', }, ], } )
    # Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' subscription = stripe.Subscription.retrieve('sub_49ty4767H20z6a') stripe.Subscription.modify( subscription.id, payment_behavior='pending_if_incomplete', proration_behavior='always_invoice', items=[{ 'id': subscription['items']['data'][0].id, 'price': 'price_CBb6IXqvTLXp3f', }] )
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $subscription = \Stripe\Subscription::retrieve('sub_49ty4767H20z6a'); \Stripe\Subscription::update( $subscription->id, [ 'payment_behavior' => 'pending_if_incomplete', 'proration_behavior' => 'always_invoice', 'items' => [ [ 'id' => $subscription->items->data[0]->id, 'price' => 'price_CBb6IXqvTLXp3f', ], ], ] );
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; Subscription subscription = Subscription.retrieve("sub_49ty4767H20z6a"); SubscriptionUpdateParams params = SubscriptionUpdateParams.builder() .setPaymentBehavior(SubscriptionUpdateParams.PaymentBehavior.PENDING_IF_INCOMPLETE) .setProrationBehavior(SubscriptionUpdateParams.ProrationBehavior.ALWAYS_INVOICE) .addItem( SubscriptionUpdateParams.Item.builder() .setId(subscription.getItems().getData().get(0).getId()) .setPrice("price_CBb6IXqvTLXp3f") .build()) .build(); subscription.update(params);
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const subscription = await stripe.subscriptions.retrieve('sub_49ty4767H20z6a'); const subscriptionUpdated = await stripe.subscriptions.update( subscription.id, { payment_behavior: 'pending_if_incomplete', proration_behavior: 'always_invoice', items: [ { id: subscription.items.data[0].id, price: 'price_CBb6IXqvTLXp3f', }, ], } );
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" subscription, err := sub.Get("sub_49ty4767H20z6a", nil) params := &stripe.SubscriptionParams{ Items: []*stripe.SubscriptionItemsParams{ { ID: stripe.String(subscription.Items.Data[0].ID), Price: stripe.String("price_CBb6IXqvTLXp3f"), }, }, PaymentBehavior: stripe.String(string(stripe.SubscriptionPaymentBehaviorPendingIfIncomplete)), ProrationBehavior: stripe.String(string(stripe.SubscriptionProrationBehaviorAlwaysInvoice)), } subscriptionUpdated, err = sub.Update("sub_49ty4767H20z6a", params)
    // Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new SubscriptionService(); var subscription = service.Get("sub_49ty4767H20z6a"); var options = new SubscriptionUpdateOptions { Items = new List<SubscriptionItemOptions> { new SubscriptionItemOptions { Id = subscription.Items.Data[0].Id, Price = "price_CBb6IXqvTLXp3f", }, }, PaymentBehavior = "pending_if_incomplete", ProrationBehavior = "always_invoice", }; subscription = service.Update("sub_49ty4767H20z6a", options);

    If payment succeeds, the subscription is updated. If payment fails, the Subscription object that’s returned contains a pending_update hash with the changes:

    { "id": "sub_49ty4767H20z6a", "object": "subscription", "application_fee_percent": null, ... "pending_update": { "expires_at": 1571194285, "subscription_items": { "id": "si_09IkI4u3ZypJUk5onGUZpe8O", "price": "price_CBb6IXqvTLXp3f", }, },

    2 Handling failed payments Client-side

    After making the update, check the pending_update hash on the subscription. If you want to be notified automatically, you can build a webhook that listens for the customer.subscription.updated event. If the pending_update hash is populated, the payment failed and the subscription will continue to cycle as if no update request was made.

    Payments often fail because the payment method is declined or because they require customer authentication. You should build logic to handle both of these scenarios.

    Use the instructions for payment failures to handle card declines. You need to attach a new payment method to the customer and then use the pay endpoint to pay the invoice that the update generates.

    Use the customer action instructions to handle customer authentication. This walks the user through the authentication process and then pays the invoice.

    A successful payment:

    • Immediately applies the changes in the pending_update hash.
    • Updates the invoice to paid.

    If payment fails again, the pending_update hash remains on the subscription with the original expiry date and no changes are applied.

    Optional Canceling or changing pending updates Server-side

    To cancel a pending update, you need to void the invoice the update created. Check the latest invoice attribute on the subscription to find the invoice ID. Then use the ID to void the invoice.

    If you want to change the values for a pending update, update the subscription with the new values. This attempts another payment. If the payment succeeds, the most recent values are applied and the outdated values are discarded. If payment fails, a new pending update replaces the existing one and the expiry date is recomputed from the current time.

    See also

    Read more about pending updates in the reference documentation.

    Was this page helpful?

    Feedback about this page?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page