Glossary

Stripe Pending Update

A Stripe pending update is a subscription change that has been requested but not applied, parked in a pending_update hash on the subscription until the invoice it generated is paid, and discarded if that payment never succeeds.

Also called: pending_update, pending_if_incomplete, payment_behavior, pending subscription update

Definition

Almost every subscription change in Stripe applies whether or not the money for it arrives.

That is the default and it is rarely what anyone wants. Stripe states it plainly: "By default, Stripe applies updates 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."

A pending update is the opt-out. When an update is requested with payment_behavior set to pending_if_incomplete and the payment fails, Stripe does not apply the change and does not leave you to unwind it. It parks the requested change on the subscription in a pending_update hash, holds the unpaid invoice open, and applies the change the moment that invoice is paid. Stripe calls it "the simplest way to ensure the customer completes payment before Stripe applies the update."

The reason it matters to anyone doing the books is what it leaves behind in the meantime. The customer asked for an upgrade. An invoice for that upgrade exists, finalized and unpaid. And the subscription is still on the old plan. A revenue figure built from subscriptions shows the old price. One built from invoices shows the new one. Neither number is wrong, and nothing has failed.

Key points

  • +Created only when an update is requested with payment_behavior set to pending_if_incomplete and the payment does not succeed.
  • +A populated pending_update hash on a subscription means the payment failed and the change has not been applied.
  • +Paying the invoice applies the change immediately and moves the invoice to paid.
  • +The default expiry is 23 hours from the update request, or sooner if a trial end or period end falls first.
  • +If nobody acts, Stripe voids the invoice and discards the update.
  • +Cancelling a pending update means voiding the invoice it created.
  • +Only available when collection_method is charge_automatically, and only for a documented list of attributes.
  • +Three sibling payment_behavior values exist, and each leaves a different trail.

What the hash holds, and how long it lives

The pending update itself is small. It carries an expiry timestamp and the changes that are waiting, which in the ordinary case is the subscription items and their new prices. Stripe describes reading it directly: "After making the update, check the pending_update hash on the subscription or listen for the customer.subscription.updated event in your webhook. A populated pending_update hash means the payment failed and your subscription update isn’t applied."

The lifetime is short and worth knowing exactly, because it decides whether a problem is still fixable when somebody notices it. Stripe documents the expiry as matching "the first occurrence of either the trial end or the earliest items.current period end", if either falls within 23 hours of the update request. Otherwise it is 23 hours from the request itself.

After that, Stripe cleans up on its own: "If you don’t take any action after an update fails, Stripe voids the invoice and discards the update after it expires." Two other events do the same thing early. Reaching a billing threshold voids the invoice and removes the pending update, and so does a subscription schedule transitioning to a new phase.

So the window in which a failed upgrade can be rescued by getting the customer to pay is usually a single day. After that the invoice is void, the change is gone, and the customer is still on the plan they were on, having asked to change it.

Resolving one, cancelling one, and replacing one

A pending update resolves by payment. Stripe is specific about the effect: "A successful payment immediately applies the changes in the pending_update hash and updates the invoice to paid." So the fix for a card decline is the ordinary one, attach a working payment method and pay the invoice the update generated, and the subscription catches up by itself.

A second failure changes nothing. Stripe states that "if payment fails again, the pending_update hash remains on the subscription with the original expiry date and no changes are applied." The clock does not restart.

Cancelling is less obvious, and it is the detail most people miss: you cancel a pending update by voiding its invoice. There is no cancel endpoint for the update. Stripe directs you to the subscription’s latest_invoice attribute to find the invoice ID, then void that invoice.

Replacing one works the same way underneath. Requesting a new update with different values updates the hash, voids the invoice belonging to the previous pending update, and creates a new invoice for the new values. Payment of that new invoice applies the most recent change. Failure produces a new pending update with a fresh expiry that replaces the old one.

That void-and-recreate pattern is the part with bookkeeping consequences. A customer who changes their mind twice about an upgrade can leave a trail of voided invoices behind a single eventual change, all of them real Stripe invoices that were finalized before they were voided.

The four payment behaviours, side by side

Pending updates are one of four values on payment_behavior, and the reason to know all four is that they differ in what they write rather than in how they feel to a customer.

allow_incomplete is the default, and has been since the 2019-03-14 API version. Stripe transitions the subscription to past_due if payment fails, and retries the payment if retries are configured. The change is applied regardless.

default_incomplete transitions to past_due without attempting payment at all, and requires explicit confirmation of the invoice’s PaymentIntent. Stripe notes that the resulting invoice has auto_advance set to false, "so Stripe doesn’t automatically attempt payment, retry payment, or finalize the subscription."

error_if_incomplete returns an HTTP 402 and does not update the subscription. Nothing is written anywhere, which makes it the cleanest to reason about and the least forgiving: Stripe notes it does not support payments that require user action, such as 3DS authentication, because it returns an error rather than a PaymentIntent awaiting action.

pending_if_incomplete is the one this page is about. Stripe flags a real boundary on it: the behaviour "doesn’t support all attributes and payment methods". It requires collection_method to be charge_automatically, and the supported attributes are limited to those that control proration behaviour or generate invoices, which covers items, price, quantity, discounts, proration_behavior, billing_cycle_anchor, trial_end, coupons and promotion codes. Anything outside that list cannot be made conditional on payment.

Why the subscription and the invoice disagree

The practical problem a pending update creates is not an error. It is a disagreement between two sources of truth that are both behaving correctly.

The invoice is finalized. It carries the proration for the upgrade the customer asked for, at the new price, dated when they asked. Any report built from invoices counts that revenue. The subscription, meanwhile, still holds the old item at the old price, because that is exactly what the pending update was for.

This is a different situation from a subscription that simply failed to collect, and it is worth telling them apart when you are looking at a past_due list. Under allow_incomplete a past_due subscription has already changed, and the money is what is missing. Under pending_if_incomplete the money is missing and the change has not happened either, so a customer who was promised more seats does not have them.

The closing state matters more than the interim one. If the invoice is eventually paid, both sides agree and the only oddity is timing. If it expires, Stripe voids the invoice, and the revenue an invoice-based report counted in the interim comes back out. A period closed in the middle of that window, on invoice-derived figures, is a period that counted something later voided.

The practical guidance is narrow: when reconciling subscription changes to invoices, treat a finalized unpaid invoice attached to a pending update as provisional, and check whether it was paid or voided before you rely on it.

What reaches QuickBooks while an update is pending

Start with what is documented, because the answer follows from the trigger rather than from any pending-update handling.

Acodei’s Invoice Sync creates a QuickBooks Invoice when a Stripe invoice is finalized, reproducing every line item and the tax lines as the mapping settings allow. It creates the payment record when the invoice is paid, on the invoice.paid and charge.succeeded events, and where that payment lands is set by your holding account configuration.

Apply that to a pending update. The invoice a pending update generates is finalized, which is the documented trigger, so QuickBooks receives an invoice for a change the Stripe subscription has not applied. That is a consequence of the documented trigger, not a feature: nothing in Acodei’s product documentation covers pending updates or payment_behavior at all, and there is no documented behaviour keyed to the pending-update events. Do not expect Acodei to detect a pending update, hold the invoice back, or reconcile the subscription against it.

The default_incomplete case falls out of the same reasoning in the opposite direction. Stripe sets auto_advance to false on that invoice, and states that it therefore does not automatically attempt payment, retry payment, or finalize. Finalization is the documented sync trigger, so until something finalizes that invoice there is nothing for the sync to act on.

The one thing worth doing on your side is watching what happens to those invoices afterwards. An expired pending update means Stripe voided its invoice, and a voided Stripe invoice is a documented event with its own handling. Whether the QuickBooks record is voided or a credit memo is written in its place depends on your configuration, so the invoice that arrived for an upgrade that never happened does not simply disappear on its own.

Want to see this on your own Stripe data?

Start a free trial

Frequently asked questions

What is a pending update in Stripe?

It is a subscription change that was requested but not applied, because the payment for it did not succeed. Stripe holds the requested change in a pending_update hash on the subscription and applies it only if the invoice it generated is paid. It exists only when the update was made with payment_behavior set to pending_if_incomplete.

How do I know a subscription has a pending update?

Check the pending_update hash on the subscription, or listen for the customer.subscription.updated event. Stripe states that a populated pending_update hash means the payment failed and the update is not applied. There are also dedicated events for the two endings, customer.subscription.pending_update_applied and customer.subscription.pending_update_expired.

How long does a pending update last?

Usually 23 hours from the update request. Stripe sets the expiry to the first occurrence of either the trial end or the earliest item current period end if one of those falls within 23 hours of the request, and otherwise to 23 hours from the request. Reaching a billing threshold or a subscription schedule phase change also ends it early.

What happens if nobody pays the invoice?

Stripe voids the invoice and discards the update after it expires. The subscription stays on its original items and prices, and the change the customer asked for does not happen. Nothing is flagged as an error, so this is worth checking rather than waiting to hear about.

How do I cancel a pending update?

By voiding the invoice it created. There is no separate cancel action for the update itself. Find the invoice through the subscription latest_invoice attribute and void it. Requesting a new update with different values does the same thing automatically, voiding the previous invoice and creating a new one.

Does a pending update work on every subscription?

No. It requires collection_method to be charge_automatically and a supported payment method, and Stripe notes the behaviour does not support all attributes. The supported attributes are the ones that control proration or generate invoices, such as items, price, quantity, discounts, proration_behavior, billing_cycle_anchor and trial_end.

Does Acodei know a Stripe subscription has a pending update?

Nothing in Acodei’s product documentation covers pending updates or payment_behavior, so treat it as unhandled rather than handled. What is documented is the trigger: a QuickBooks invoice is created when a Stripe invoice is finalized. The invoice a pending update generates is finalized, so it reaches QuickBooks like any other, describing a change the subscription has not applied.

Why does my QuickBooks invoice show an upgrade the customer is not on?

If the update used pending_if_incomplete and the payment failed, the invoice exists and the subscription change does not. The documented sync trigger is finalization of the Stripe invoice, so the invoice syncs on its own timetable. Check whether that Stripe invoice was later paid or voided before treating the amount as settled revenue.

What customers say about running Stripe through Acodei

Stripe Verified Partner BadgeQuickBooks Intuit Badge
If you're testing out all the different Stripe/QuickBooks integration apps right now, let me save you some time. This one is the best one by far.
RyanOwner at Indie Music Academy
Works well and is really helpful for massive transactions. The support is really fast and helpful. 100% recommended.
AndresCo-founder and CEO at Kanguro Collections and Reinsurance

Ready to try Acodei?

Connect Stripe to QuickBooks Online in minutes and let the fees, refunds, and payouts land where your accountant expects them.