Root Cause
Stripe changed the format of the web addresses it generates for its Customer Portal, the hosted page where you update a card or edit your billing details. The link used to carry a session identifier in its path. Stripe moved that identifier into a query parameter, the part of a web address that comes after a question mark. Stripe didn't publish a changelog entry for the change.
Our own code is the reason that change broke anything. For about three years we'd taken the link Stripe handed us and added extra path segments onto the end of it, so that clicking "Update Method" would drop you straight into the right form instead of the portal home page. That worked while the identifier sat in the path. Once it moved into a query parameter, adding anything to the end of the address corrupted the identifier, Stripe couldn't match it to a real session, and you got its page-not-found error.
Stripe documents a supported way to open a specific section of the portal, and we weren't using it. We'd built on behavior we'd observed rather than behavior Stripe published, and that approach had been copied into three separate places in our front end. All three broke at the same moment.
Customer Impact
If you tried to update your payment method or your billing information, you got a page reading "This page could not be found" instead of the form you were expecting. It wasn't limited to a plan, a region, or an account type. Anyone who clicked through hit it. The problem had already been running for some hours before we declared an incident, and since Stripe published nothing about the change, we can't tell you when it actually started.
Every route into billing management failed: the "Update Method" button on the billing page, the actions for updating billing information, adding an address, and adding a tax ID, the "View All" button for invoices and receipts, and the older billing page some accounts still use along with the billing banner in the app. Plan changes and channel purchases kept working throughout. We can say that with confidence rather than inferring it from the quiet, because those flows never touched the affected link.
Four customers wrote in to support about it. That count is low by an amount we can't measure, since nothing on our side recorded these failures, and the only people we can count are the ones who chose to tell us.
If your card was expiring or had already been declined, this was a window in which you couldn't do anything about it, and we're sorry.
Steps to Resolution
We reproduced the error and confirmed it wasn't tied to any particular account.
We looked at our own recent deploys, feature flags, and Stripe configuration first, on the assumption that something we'd shipped had caused it. Nothing in the preceding period lined up. The last change to this flow was more than a year old.
We compared the address the billing page was sending you to against one that worked, and found the extra segment on the end. Taking it off made the link resolve.
We worked through the other billing buttons and found each failing the same way, which told us this was every entry point rather than one broken button.
We shipped a fix that opens the address Stripe returns exactly as Stripe returns it. The tradeoff is that you now land on the portal home page rather than the specific form you asked for. A portal that works beat a deep link that didn't.
Our first deploy of that fix failed. We caught it, pushed the fix through, and confirmed the billing flow was working in production before we called the incident resolved. We also made already-open tabs pick up the fix, so you didn't need to refresh to get it.
Key Learnings
- We shouldn't have been modifying a web address we don't own. Treating a link from an external service as a string to append to ties our code to a format that service can change whenever it likes, which is what happened here. We're moving to the mechanism Stripe supports, where we name the section we want at the moment we request the link, and the link comes back pointing at the right place. That's a tracked action item from this incident and it's assigned.
- Nothing in our own systems told us this was broken. Stripe served the error from its own pages, so no error rate, log, or alert on our side moved at all. The first sign of any kind was a customer writing in, and more than three hours passed between that message and our declaring an incident. We're adding an automated check that requests a portal link on a schedule, follows it, and alerts us when the page doesn't load. That work is tracked and assigned.
- Deep links into the billing forms are gone until we rebuild them properly. For now you land on the portal home page and have to find the payment method or billing address form yourself. That's worse than what you had, and it's temporary. Restoring it is part of the same tracked work.