Over the past decade almost everything about how we build software has changed. One thing has not: you are either building an API or consuming one. That is the whole job most days, only dressed in different clothes. And the difference between an API people adopt and one they quietly route around almost always comes down to a single question – who did you build it for?
There are good maps for the mechanics of this. Martin Fowler's write-up of the Richardson Maturity Model is the one I still hand to people who want to reason about REST properly. But scoring well on a maturity model is not the same as building something developers actually want to use, and that gap is where most of the pain lives.
The API I Hated to Integrate
I can tell you exactly what a bad API feels like from the inside, because I have integrated plenty of them. The documentation was sparse. Versioning was an afterthought, bolted on once it was already too late to do well. The error messages were a cryptic puzzle that told you something had gone wrong without ever telling you what, or where, or what to do about it. I did not enjoy integrating it. More often I simply lost interest somewhere in the middle, which is worse, because by then I had already decided how I felt about whoever built it.
I have watched it from the other side too. A team spends months building an API, ships it, and then cannot understand why adoption is so low. The answer is almost always that it is too complex, or poorly documented, or both. Here is the uncomfortable reframe that changes how you build: if developers are your users, then their frustration is your API's failure rate. Not a soft metric you can explain away. The failure rate.
An Acquired Taste
When you try an unfamiliar cuisine, one of a few things happens. You like it, or you do not, or you wanted to like it and slowly trained your palate until you did. That last one has a name. We call it an acquired taste.
Our own code works much the same way, except we skip straight to loving it, often when we should not. We are fluent in our own choices. We understand the shortcut because we are the ones who made it. But an API is not built for us. It is built for someone else, and they do not get to read our minds, only our contract. As developers, we have to deliberately acquire the taste of our own consumer, which is unnatural and worth forcing anyway. It is also, in a sense, the question GraphQL forced on the whole industry – who is this interface really serving?
Which is why I keep coming back to a deceptively simple exercise:
- Build the API.
- Switch hats.
- Try to integrate it as a frontend, mobile, or data engineer who has never seen it before.
- If you hate it, congratulations. It is not good enough yet.
The Benchmark
When I judge an API now, mine or anyone else's, I ask four questions:
- Are the contracts explained against real business use cases, including not just the happy path but the exceptional ones? An API that only documents success is documenting half of reality, and consumers live in the other half.
- Is there a developer ecosystem where someone can actually try the API by following the very documentation you shipped? Reading is not believing. Doing is.
- When an integration breaks, in development or in production, how quickly can a developer find the cause? Does your error catalog and documentation lead them to the fix, or at least to understanding what they got wrong, without having to open a support ticket and wait?
- How hard is it to move from one major version to the next? Did you provide real upgrade guidance and insight, or a changelog and good luck?
Treat the API as a Product
All of it rests on one shift in how you see the thing you are building. An API is not a technical artifact you emit on the way to the real work. It is the product. And like any product, it has to do three things:
- Solve a real problem, rather than quietly create new ones for the people who adopt it.
- Offer a smooth onboarding experience. A developer should not need therapy after integrating you.
- Be versioned responsibly, because a careless breaking change is just a way of making your users angry on a schedule.
If you want to see what that looks like done well, study the teams that treat their API as the product rather than a side effect of one. The short list I send people, not to copy but to feel the bar, looks like this:
- Stripe and Twilio – often held up as the standard for a reason.
- PayPal and X (Twitter) – payments and platform at scale.
- Spotify, LinkedIn, and Google – consistent, explorable, and patient with newcomers.
None of them got there by accident, and none of it is the part of the work that ever feels urgent. That is exactly why it is the part that separates them.
We Went API-First
Good intentions, unfortunately, do not survive contact with scale on their own. The pattern is always the same. A team builds an API, ships it, and moves on. Then one day a consumer breaks. Another cannot upgrade. And suddenly you are fighting fires across three versions and six teams, where every fix you make for one of them risks lighting a fire under another.
Whoever your end customer is, your real consumers are very often the developers consuming your APIs, and what those APIs owe them is more than data and actions. They owe consistency across platforms, a contract that holds as a promise to the mobile, web, and data teams, and predictable behaviour even as the systems underneath keep evolving. Delivering that reliably needed more than better specifications or stricter reviews. It needed a cultural shift, and the name we gave it was API-First.
At a digital-banking platform where I led architecture, we made that shift across seventeen squads, more than a hundred and fifty engineers, and four regions. The principle was easy to say and hard to live: when your business model depends on APIs – powering mobile apps, integrations, partnerships – the APIs are first-class citizens. Not designed after the frontend. Not squeezed in after the MVP. First.
What It Actually Took
Treating APIs as first-class meant making a few things non-negotiable that most teams leave to good intentions:
- Backward compatibility became the rule, not the courtesy. We built automated breaking-change detection into the CI/CD pipeline. If a change would break a consumer, it did not ship. Not "we filed a ticket." It did not ship.
- Contract testing became non-negotiable. We introduced consumer-provider contract testing that was language-agnostic, reusable, and enforced at every stage, so a promise made to a consumer was verified rather than assumed.
- The lifecycle became a shared roadmap. Versioning, specification, release, deprecation, and retirement were published, so every stakeholder knew what was coming and when, and could roll out or phase out gracefully instead of by surprise.
Underneath all of it was one idea: the API lifecycle and the developer experience are the same thing. A well-designed API is not merely functional. It is enjoyable – clear docs, real testability, meaningful errors, and contracts that stay consistent as everything else changes.
What Changed
The results were not subtle. More confidence shipping. Faster integration for the teams consuming us. Fewer rollbacks. And the one I cared about most: happier teams, because nobody was being woken up by a breaking change they never saw coming.
Adopting API-First was never just a process tweak. It was a mindset shift, a process shift, an organisational shift, and a delivery shift all at once – a genuine change in how we developed, tested, built, and deployed. That kind of change is expensive, slow, and occasionally unpopular while it is happening. It was also, with very little doubt in hindsight, worth it.
Your users will notice. And they are developers, so they will also remember.