Most API breakage isn’t malicious. It’s a Tuesday deploy that looked safe, a field someone renamed to be “clearer,” a default that changed under everyone. The damage is the same either way: somebody’s integration goes quiet, and they find out from a user. We built versioning so that never lands on you.
Who breakage actually hits
When an API changes shape, the person who pays isn’t the team that shipped the change. It’s the developer two time zones away who pinned a code path to the old response and went on with their life, exactly as they should be able to. They did everything right. The contract moved under them.
On maviapi this is doubly tricky, because an endpoint can change for a reason nobody on our side chose: the source website redesigned, and our build agent re-derived the extraction to keep up. We needed a model where “the endpoint healed itself” and “your response shape is guaranteed” are both true at once.
Versions are immutable
The rule is simple. Every build of an endpoint produces a version, and a version is frozen the moment it exists. We never edit one in place. A repair, a new field, a better selector: each of those is a new version with its own number. Nothing you’ve already integrated against is ever rewritten.
Every response tells you exactly which one served it:
HTTP/2 200
content-type: application/json
x-maviapi-version: 4
x-maviapi-stale: falseThat header isn’t decoration. It’s the thing that lets you notice, in your own logs, that you started getting version 4 last week, and decide on your own schedule whether you care.
Promoting safely
Each endpoint has one active version, and that’s what an ordinary request gets. When a new build lands, it doesn’t become active automatically. It sits there, fully callable, waiting for someone to look at it. From the dashboard you can diff the new version against the active one, field by field, and see exactly what moved before you change anything for real callers.
Want to try a non-active version without touching production? Ask for it by number:
curl https://api.maviapi.com/v1/sites/github/repo?owner=kuzenlabs&name=maviapi \
-H "Authorization: Bearer $MAVIAPI_KEY" \
-H "x-maviapi-version: 5"Same key, same endpoint, a different frozen build. You can wire that into a staging environment, compare it against what you get today, and only then promote. Promotion is one click, and it’s just flipping which version the pointer names. Roll it back the same way.
Pinning and the active version
Two postures, both legitimate:
- Track active. Send no version header and you always get the current best build, repairs included. Good when you want maviapi to keep the endpoint working and you trust the contract to hold its shape.
- Pin a number. Send
x-maviapi-versionand you get exactly that build until you change the header. Good when you’d rather move deliberately and review each new version yourself.
Pinning protects you from shape changes, not from the web. A pinned version still fetches live data; it just guarantees the structure you parse. If a site disappears entirely, no version can conjure it back, which is exactly when the x-maviapi-stale header earns its keep.
How we use it ourselves
We dogfood this on our own catalog. The Reddit and Hacker News endpoints have each been through several versions as those sites shifted, and not one of those moves broke a caller who pinned. Internally the rule we hold ourselves to is boring and absolute: if a change would alter a response shape, it’s a new version, full stop. Boring is the point. Versioning is one of those features that’s working precisely when you forget it’s there.
Started maviapi after one too many 2am scraper fires. Writes about the product, the bets behind it, and the parts of running an API company nobody warns you about.
More from Musab