API versioning is one of those subjects that sounds academic right up until the moment a customer's integration breaks in production because you changed a field name on a Tuesday afternoon. I have had that call. It is not a fun one to take, and it is entirely avoidable if you decide on an approach before you actually need it rather than after somebody has already been burned.
I have built and maintained public APIs for CampSuite and for a good number of client integration projects over the years, and the pattern I see most often with small teams is the same one I see with rate limiting. Nobody sits down and decides deliberately, so the decision gets made by accident, usually under pressure, usually badly. I wrote about that exact trap in my guide to API rate limiting for small SaaS teams, and versioning suffers from the same lack of a plan.
Why Small Teams Avoid Thinking About This
Versioning feels like a big architecture decision, so it gets pushed to one side while the team focuses on shipping features that customers are actually asking for. That is understandable. Nobody wakes up excited to design a deprecation policy. But an API without any versioning strategy is not an API without a policy, it is an API with an accidental policy, and that policy is usually "we will break things whenever we need to and hope nobody notices."
The other reason teams avoid it is that most of the writing on API versioning is aimed at companies running dozens of services with thousands of external consumers, where the tooling and the process genuinely need to be heavyweight. If you are a small SaaS team with a handful of integration partners, copying that approach wholesale is as wasteful as building a distributed rate limiter for an API that gets ten requests a second.
The Three Approaches That Actually Exist
Strip away the naming conventions and there are really only three ways teams handle this, and each one has a genuinely different cost profile.
URL Path Versioning
This is the one everybody recognises, where your endpoint becomes something like /v1/customers or /v2/customers. It is blunt, it is obvious to anyone reading your API documentation, and it is easy for client applications to pin themselves to a version and stay there. The downside is that you end up maintaining parallel versions of the same logic, which gets expensive fast if you are not disciplined about what actually changes between versions.
Header Based Versioning
Here the version lives in a request header rather than the URL, so the same endpoint can serve different response shapes depending on what the caller asks for. It is tidier in theory and avoids duplicate routes, but in practice it is harder for integration partners to reason about and harder to debug when something goes wrong, because the version is not sitting there in plain sight in the URL or the browser address bar.
Evolve In Place With Additive Changes Only
This is the approach I actually default to for most small SaaS products, and it is the one people talk about least. The rule is simple. You are allowed to add new fields to a response. You are allowed to add new optional parameters to a request. You are never allowed to remove a field, rename a field, or change what an existing field means. Well built client applications ignore fields they do not recognise, so additive changes cause no breakage at all, and you avoid maintaining parallel versions of anything.
What I Actually Recommend
For the vast majority of small teams, start with additive only changes and do not introduce a version number at all until you hit a change that genuinely cannot be additive, such as restructuring how authentication works or fundamentally changing what an endpoint does. When that day comes, and it usually does eventually, add a single explicit version in the URL path, keep the old version running exactly as it was, and give it a genuine end date rather than an open ended promise to support it forever.
The end date matters more than people think. An old API version with no sunset date becomes something your team supports indefinitely, and every future change now has to consider its effect on customers you cannot even remember signing up. I set a fixed window, usually twelve months, communicate it clearly, and hold to it. Customers respect a clear deadline a lot more than a vague promise that gets extended every time somebody complains.
Communicating Breaking Changes Properly
The technical side of versioning is honestly the easy part. The part that actually determines whether your integration partners forgive you is how you communicate a breaking change. Send a direct email to every account with an active API key, not just a changelog entry nobody reads. State exactly what changes, exactly when, and exactly what the integration needs to do differently. If you can, add a response header on the old version that flags it as deprecated, so any team using proper tooling gets an automatic warning long before the cutoff date arrives.
I have seen a client relationship genuinely sour not because of the technical change itself, but because the customer found out about it from a support ticket rather than from the vendor. Good communication on a breaking change costs you half an hour of writing. A silent one costs you the account.
My Honest Take
Most small SaaS teams do not need a version numbering scheme, they need a discipline of not breaking existing consumers by accident, and a plan for the rare occasions when a genuine breaking change is unavoidable. Additive changes get you a long way with very little overhead. When you do need a real version bump, treat it as a serious event with a fixed sunset date and honest communication, not a routine you repeat every few months because nobody planned the API properly the first time.
If you are building out public API infrastructure and want a second opinion on whether your approach will actually hold up as customers start depending on it, this is exactly the kind of decision I help clients think through in development consulting. It is also the sort of unglamorous groundwork I cover in The 28 Day Startup, because the businesses that keep their integration partners happy are usually the ones that got the boring decisions right early.


