Photo: Google Gemini · AI-generated
Most software decisions are reversible. You pick a framework, regret it, and replace it. The cost is yours and it stays inside your building.
Publishing an API is different. The moment someone integrates with it, you have made a commitment to a stranger — and you usually cannot reach them to renegotiate.
That asymmetry is worth understanding before you expose anything, because it changes what “done” means.
You cannot see who depends on you
Internal code has a known blast radius. You can search the repository and find every caller.
An exposed API does not work that way. Somewhere there is a partner who integrated eighteen months ago, wrote no tests against you, and has not thought about your service since. They will not read your changelog. They will find out you changed something when their production breaks, and their first call will be to you.
We built CarLicence, a real-time licence disc renewal platform that South African businesses integrate directly — into their own websites, mobile apps, POS systems, and even ATMs. The value proposition is that a partner can go live in hours rather than weeks.
Look at what that implies. Every one of those partners has put our behaviour inside their product, in front of their customers, under their brand. Some of it runs on hardware nobody updates. The integration being fast to adopt is the easy half; the hard half is that it then has to keep meaning the same thing, indefinitely.
The promise is bigger than the endpoints
Teams tend to think the contract is the documented request and response. It is much wider than that.
You are also promising the shape of your errors, because someone has written a handler that branches on them. The rough timing, because someone set a timeout. The ordering, the rounding, the null-versus-absent distinction, the exact spelling of a status string someone compared against. Anything observable becomes load-bearing, whether you documented it or not.
This is why “we only changed an internal detail” is a sentence worth distrusting. If it is observable through the interface, it was never internal.
Build for the rewrite you have not planned yet
The useful discipline is to treat the interface as older and more permanent than whatever implements it. Assume the implementation gets replaced and the interface does not.
That is not hypothetical. Mobile ERP is the same idea from the consuming side: a warehouse app for a Sage 100 add-on vendor that moved off end-of-life Windows CE onto native Android, while continuing to talk to Sage 100 exactly as it always had. The entire platform underneath changed. The contract did not, which is precisely why customers could swap hardware without changing anything about how they work.
A stable interface is what makes the layer beneath it replaceable. Teams that entangle the two end up unable to modernise without a coordinated migration across every consumer — which is how a rewrite becomes a five-year negotiation.
Versioning is how you keep the promise and still move
None of this means freezing forever. It means change becomes something you schedule rather than something you spring.
Version the interface, so a breaking change is a new address rather than a broken one. Announce deprecation with a real date and hold to it. Keep the old version running past the point it feels reasonable, because someone’s release cycle is slower than yours. And know who is still on it, which requires measuring rather than assuming.
That last part is where most of the discipline actually lives: you cannot retire a version safely if you cannot see who is on it, so per-consumer usage data is not analytics, it is a prerequisite for change.
Monitoring is part of the contract
The final obligation is to notice problems before your integrators do.
If a partner’s customer discovers your degradation first, you have not just shipped a bug — you have spent the credibility that made the integration worth adopting. Availability, latency and error rates on an exposed API are not internal metrics; they are the thing you promised, measured.
Doing this properly is unglamorous and permanent. It is also what separates an integration that survives the next rewrite from one that quietly becomes the reason a rewrite cannot happen.
If you are exposing an interface others will build on, we should talk.
