The version your app runs on has an expiry date
The connection between your shop and your accounting system was built two years ago. It has run every day since. Nobody has touched it, and nobody has needed to.
Then one Thursday afternoon a date passes, and the connection keeps running. Orders keep arriving. No alert fires, no error appears, no ticket is raised. Something has changed anyway: the answers your integration receives are no longer coming from the version it asked for.
That is the whole subject of this article, and the reason it takes more than "keep your software updated". Software that breaks gets fixed. This does not break.
Versions have an expiry date, and it is published
The platforms your business connects to release their interfaces in versions, and an integration is normally pinned to one so that it keeps behaving the same way. Those versions do not last forever, and on the better-documented platforms the exact expiry is printed in a table.
Shopify's policy is generous and specific: "Each stable version is supported for a minimum of 12 months, with at least nine months of overlap between consecutive versions", and a new one appears "every three months at the beginning of the quarter, at 5pm UTC". The overlap is there for exactly the reason you would hope: "Because versions overlap by at least nine months, you'll always have time to update before removal."
The published table is worth looking at with a business eye rather than a technical one, because two rows have dates on them that a reader can check this week. The version named 2025-07 was accessible until 16 July 2026 - under two months before this was written. The version named 2025-10 stops being accessible on 16 October 2026, which is a few weeks from now.
Notice the column heading Shopify uses: not "supported until" but "Accessible until". And notice that the entry is not a date but a moment: 15:00 UTC. Three in the afternoon, mid-working-day in Europe, first thing in North America.
Nobody schedules a maintenance window for three in the afternoon on a Thursday, because nothing is going to fall over. That is precisely the problem, and it is worth being fair about whose problem it is. Shopify keeps its promise with room to spare: 2025-07 was released on 1 July 2025 and stayed reachable for just over twelve months. The policy is not stingy. The enforcement of it is silent, which is a different thing.
On the day it expires, nothing happens
Here is the sentence the whole article rests on, verbatim from Shopify's
versioning documentation: "If your app targets an inaccessible version, Shopify
falls forward and responds using the oldest accessible stable version. For
example, requests to a retired 2026-10 are served as 2027-01."
Falls forward. Not refuses, not errors, not warns. Answers, as something else.
The older documentation for its legacy interface says the same thing in different words, which is a useful confirmation that this is longstanding behaviour rather than a recent decision: "if your app uses a stable version that is no longer supported, then Shopify falls forward and responds to your request with the same behaviour as the oldest supported stable version."
To be sure this was not simply an undocumented failure, I had the complete reference of status codes read through - every code the platform returns, from the successful ones through the various refusals to the server errors. There are twenty-seven of them and not one mentions API versions. There is no version-expired code, because there is no version-expired event to report. The call succeeds.
Sit with that for a second in business terms. Your integration asks a question in the way it has always asked it. It receives a complete, valid, successful answer. The answer is shaped according to rules that came into force after your integration was written, and neither end of the conversation says anything about it.
The same applies to messages the platform pushes to you, which for most small businesses is the more important half: "Webhook payloads are versioned the same way as API responses. Shopify falls forward when your selected version becomes inaccessible..." So a differently-shaped message starts arriving at an address you own, unprompted, and whatever is listening at that address carries on doing its job with it.
The only signal is in every response, which is why nobody sees it
There is a signal. It is worth being precise about what it is, because the precision is the point.
Every response carries a line naming the version that actually served it. The documentation explains what to do with that line: if it differs from what you requested, your app is targeting an inaccessible version and the platform has fallen forward to the default.
Read that as a statement of responsibility rather than as a feature. The platform is not saying it will tell you. It is saying the information is present in every single response, and noticing it is your job.
That line is sent on every successful call, whether or not anything is wrong. It carries no flag. It does not change shape when the fall-forward happens; only its contents change. Detecting the expiry means having written something that compares the version you asked for against the version you got, on every call, and complains when they differ.
Almost nobody writes that, and the reason is entirely understandable: until the single afternoon it matters, those two values are always identical. Code that checks it produces nothing for a year and then produces one message. And anybody disciplined enough to have written that check was probably disciplined enough to have kept the version current in the first place.
The same line rides along with pushed messages too, sitting in a list of routine metadata beside the message type and its identifier, with nothing to mark it out as the tripwire it is.
Getting it obviously wrong is safer than getting it right
This is the part worth explaining to whoever maintains your systems, because it inverts an instinct that is otherwise reliable.
A version string that is nonsense - a typo, an invented date, a copy-paste mistake - was never a real version. The request has nowhere to go, and whatever happens next, it happens on the first request rather than a year later. Somebody finds out during the coffee after the deploy.
A version string that was real and has since expired is still a recognised string. The platform knows exactly what you meant. It simply answers as something else.
So the dangerous case is not carelessness. It is care: getting it right, pinning it deliberately, documenting it, and then waiting fourteen months. The integration that was set up properly and left alone is the one that fails silently, and the sloppy one fails on the first afternoon and gets fixed.
I should be careful here, because I could not confirm from the platform's own documentation what an invalid version string returns, and I am not going to invent a code for it. The asymmetry stands on the documented half: expiry produces a successful response from a different version. That is the half that matters.
If you would rather have somebody go through the connections your business runs on and put a date and a number against each one, that is the process audit. $299, three business days, and a written map you keep whether or not you hire us.
And this is not one platform's quirk
It would be easy to read all of the above as an oddity of one company. It is not, and the second example is the one that should worry a small business more.
Intuit's documentation for the QuickBooks Online accounting interface describes the same behaviour and says it more bluntly than Shopify does. Support for the older minor versions was discontinued from 1 August 2025, and then: "In your API request, if you specify a value for the minorversion parameter that is less than 75, it will be ignored and the system will respond with data corresponding to minor version 75."
It will be ignored. You keep sending a parameter naming a version that no longer exists; the parameter is discarded; you receive a successful response shaped according to a different version. Your pin has become a decoration.
Shopify falling forward changes the shape of an order. Intuit ignoring your version changes the shape of an accounting record. For a business whose books are connected to anything, that is the more consequential of the two.
The other platforms I had checked do it differently, and the differences are worth knowing because they determine whether you will find out.
HubSpot publishes a schedule and then errors. Its date-based versioning gives "18 months of support for each version instead of the previous 90-day minimum deprecation notice", with breaking changes confined to twice a year, and when endpoints are removed they "begin returning HTTP 404". But it also has the other behaviour, and honesty requires printing it: some older endpoints are kept alive while the data is withdrawn, so that they "will continue to function, but will no longer return list membership". A successful response with the substance missing is the same trap wearing a different hat.
Twilio supplies the reassuring data point. Its current interface version carries a date from 2010 and is still the live one, sixteen years on. Its one retirement in that time was a hard failure with long notice: "After December 15, 2023, any requests sent to Twilio's 2008 API will fail with 404 responses."
Xero retires individual endpoints rather than whole versions, and errors when it does: a changelog entry dated 4 May 2026 states that "All Accounting Activities endpoints will now return errors."
Stripe I am leaving blank on purpose. Its versioning and upgrade documentation was read in full and it neither states that old versions are retired nor states that they are not. The accurate sentence is that no retirement schedule is published, which is not the same as a guarantee, and you should not plan as though it were.
The useful conclusion is not that one platform behaves badly. It is that there are two possible behaviours, both defensible, and you cannot tell which one applies to your integration without going and reading. On a platform that errors, an expired version is a bad morning. On a platform that substitutes, it is a quiet drift that surfaces in a reconciliation months later, if at all.
What actually changes when a version rolls
Version changes sound abstract until you see one. Here are two from Shopify's own changelog, both landing in versions a business might well be running through right now.
On 6 March 2026, an identifier was removed from checkout messages and replaced with a different one, and the same substitution was made across seven kinds of order message - created, paid, cancelled, fulfilled, partially fulfilled, updated, and link requested. The stated reason is reasonable housekeeping: to "simplify and standardize our checkout references" and to make integrations "reference checkouts using the same identifier".
Now think about what an order message does at a small business. It creates the invoice, files the job, tells the warehouse. An identifier quietly going missing from it does not produce an error. It produces a record with a blank field, or a lookup that matches nothing and creates a duplicate, or a job that never gets linked to the order it belongs to. Which of those you get depends entirely on how the receiving code was written, and nobody wrote it with this in mind.
The second example is larger. A changelog entry dated 6 July 2026 removes an entire type from one of Shopify's interfaces in the version landing next month, along with everything hanging off it. There is no replacement within the same interface; developers are directed to a different one for live checkout state and to a different query again for purchase history.
That is the detail that should reset expectations about what "upgrade to the new version" costs. It is usually imagined as a rename. Sometimes the honest answer to "where did my data go" is: another interface entirely. That is not a fifteen-minute job, and it is why the nine-month overlap exists.
There is one more thing worth knowing if you plan to keep track of this yourself. Shopify's release-notes index now carries only a couple of recent versions and states that per-version release notes are no longer published, directing readers to a filterable changelog feed instead. The single document that used to answer "what changed in this version" does not exist any more. You are expected to subscribe.
The warning goes to a role, and the role may be empty
This section is the reason a business owner should read the rest.
Notifications about version changes are addressed to a designated technical contact, and the documentation is careful about how firmly it promises them: the emergency developer contact "might be notified", and that sentence is scoped to imminent breaking changes rather than to the routine expiry of a version you pinned. Shopify describes the purpose plainly - the contact exists so that it can "communicate critical, targeted technical information to developers who maintain Shopify apps" - and describes the ideal recipient as somebody who monitors their inbox regularly, understands the technology, and is responsible for the integration.
For an app you installed from a marketplace, that person works for the app's maker, and you are not in the loop at all. You become involved only at the punishment stage: warnings shown in your admin, blocked installations, and, in the platform's own words, the possibility of "notifying users that the app doesn't work, or providing users with alternative app recommendations". By the time you hear anything, the situation has been going on for a while.
For something built for you - by a freelancer, an agency, or the technically minded person who used to work there - the contact is chosen from a list of your own staff and collaborator accounts. And here is the documented detail that should make any owner sit up: if that developer account is later deleted, the store owner becomes the app developer by default.
Read that with a real business in mind. The freelancer builds the integration and is set as its developer contact. The engagement ends. Six months later somebody tidies up the staff list and removes an account that has not been used since spring. From that moment any deprecation notice goes to the owner: a person who has never opened a developer dashboard, does not know what 2025-07 means, and has no code.
Nothing is lost. Nothing bounces. No warning fires to say that the warnings now have nowhere useful to go. The system is working exactly as designed, and the outcome is that the notice lands in the inbox of the one person who cannot act on it. This is the same underlying question as what you should get when an automation is handed over to you, and here it has a specific new item: who is named as the technical contact, and does that person still work with you.
There is a self-service check available, and it has two limits worth naming. The documentation describes it in two ways on the same page - as the calls made by "the authenticated app" and as the calls "your custom apps have made" - and on the narrower reading it cannot tell you anything about the other applications on your store. It is also documented as available only for custom apps.
The quieter your automation, the worse the monitoring
A short one, and it inverts another instinct.
Shopify's health report reflects calls made in the last fourteen days, and a status persists for up to fourteen days after the offending calls stop.
So a busy integration that runs hundreds of times a day shows up clearly. A quiet one does not. The monthly reconciliation job, the quarterly export, the seasonal connector that only wakes up in November - these can sit entirely outside the window between runs, invisible to the report that exists to catch them.
Which is backwards from what an owner would assume, and it maps onto risk in exactly the wrong direction. The connection you think about every day is the one being watched. The one you have forgotten about, which is by definition the one running on an old version, is the one that leaves no trace to watch.
This is why a written list matters more than a monitoring screen. A register of what your business has automated is only useful here if it has a column for the version each thing is pinned to and the date that version stops being accessible, and most registers do not.
The dashboards disagree with each other
The picture above assumes the monitoring tells the truth. In practice, developers report that the merchant-facing warning and the developer-facing report frequently disagree, and this is worth knowing before you rely on either.
On 13 October 2025, in Shopify's developer community, somebody reported a deprecation banner for a version they were not using: "We're seeing a 2024-07 API deprecation warning banner for one of our apps, but we're already on 2025-04", with no recent changes deployed. A colleague added that they did not make calls to the endpoints in question anywhere in the app. A Shopify staff member replied the next day that the banner "usually disappears within 7 days" and two days later that they were "looking into this further as a possible issue on our end". Ten days after the original report, the banner was gone and the developer dashboard was still showing the problem.
Ten months later the same contradiction was still being reported. On 16 July 2026 a developer described a "This app may not work as expected" message appearing to merchants while the health report showed no breaking-change calls at all. A reply the following day: "It's nothing but a headache...It really needs to stop. It does nothing but lie to merchants and cause confusion." Another the same day: "Everything looks clean in the dev dashboard." A week later somebody reported the badge finally disappearing after upgrading, "our dashboard showed no deprecated API calls" throughout.
And the mismatch runs in the other direction too. On 4 May 2026 a developer reported receiving a deprecation notice by email about a version while the dashboard "says that our app hasn't made any deprecated API calls in the last 30 days"; two days later another confirmed the same: "I received an email notification, but there are no corresponding logs in API Health."
None of this means the platform is careless. It means that for a small business the practical answer to "is this a real problem" cannot be settled by looking at one screen, and the person who could settle it by looking at the code may no longer be reachable.
Even the signal can lie
One more, because it is the exception that makes the rule worth stating carefully.
In April 2026, developers reported that pushed messages were intermittently
arriving in the wrong shape. On 13 April 2026 one wrote: "Since last Friday
2026-04-10 around 14:00 UTC, at least checkouts/update webhooks have been
intermittently arriving with the wrong API version payload." The subscriptions
were pinned correctly. The line naming the version said the correct thing. The
identifier that had been removed in the newer version was missing anyway. A
second developer reported the same thing happening to identifiers overnight.
A Shopify engineer confirmed the next day that the field "should still be present for subscriptions on API versions older than 2026-04", and explained the cause: if a store had another subscription on the same message type resolving to the newer version, the removal was applied to all subscriptions on that store. A fix rolled out over the next day or two.
That was a bug, it was acknowledged, and it was fixed quickly. The reason to include it is narrower: the one signal you are told to check can, occasionally, be correct while the content is not. Which is a good argument for the boring answer - knowing what version each of your integrations is pinned to, and when that version expires, written down somewhere a person reads - rather than for building something clever to detect it.
What to check in your own setup
Make a list of what talks to what. Every connection between your systems, including the ones built by somebody who has left. This is a shorter list than people fear and longer than they expect.
For each one, find two facts: which version, and until when. Both are usually published. Neither is usually written down anywhere in the business.
Find out who is named as the technical contact on each. Then check that the person still works with you and still reads that inbox. If a developer account was ever tidied up, assume the notices now come to the owner.
Ask what your platforms do when a version expires. Two behaviours exist. The answer determines whether an expiry is a bad morning or a slow drift, and it is a different answer for each vendor you use.
Put the expiry dates in the calendar of a person, not a system. A quiet integration is invisible to the monitoring precisely because it is quiet. A date in a diary does not have that problem.
Ask what would have to change if a field disappeared. Not hypothetically - pick the order or invoice message your business depends on most, and ask what your side does if one identifier in it stops arriving. The answer is usually "nothing visible", which is the answer that costs the most.
When this stops being a settings question
For a business with one integration, built recently, by somebody you can still call, the checks above are the whole job. Find the version, find the date, put it in a calendar.
It stops being that when the connections outnumber the people who understand them. Five integrations built at different times, on different platforms, by different hands, each pinned to its own version with its own expiry and its own answer to what happens on the day. Some will error and be fixed within the hour. Some will quietly begin answering from somewhere else, and the first sign will be a number that does not reconcile in a quarter's time. This is the far end of the problem described in why automations fail silently: not a failure that goes unreported, but a change of behaviour that was never a failure at all. And it is the maintenance cost that no-code tools postpone rather than remove.
Working out which of your connections are on a clock, and what each would cost on the day it runs out, is what the process audit settles: what can be automated, in what order, and what each piece is worth, in writing, in three business days.