Versioning and stability

The API is versioned in the URL, additive-only within a version, with breaking changes reserved for a new version and a dual-run window.

The API is versioned in the URL. Everything lives under /v1, and we hold that path to a strict compatibility promise so an integration you write today keeps working.

Additive-only within a version

Inside /v1, changes are additive only. We may add new endpoints, new optional request fields, and new fields on responses. We do not change the shape of an existing field, remove one, rename one, or change what an existing value means. Write your client to ignore fields it doesn't recognise and it won't break when we add them.

Breaking changes get a new version

A change that would break an existing caller — removing a field, changing a type, altering required inputs — goes in a new version, /v2, at a new URL. When that happens we dual-run: /v1 and /v2 are served side by side for a migration window, so you move over deliberately rather than all at once.

What counts as the contract

The URL surface isn't the whole promise. These are part of the versioned contract and follow the same rules:

  • Tool names — the MCP tool identifiers agents call.
  • Event names — the event types on webhooks and the event stream.
  • Error codes — the stable code on every error, and the type URI it resolves to at https://docs.hannu.africa/errors/<code>.

A code, a tool name, or an event name won't change meaning inside a version. New ones may appear; existing ones stay put.

Pin to the version, match on codes

Call the version explicitly in the path (/v1/...) and branch your logic on the stable code and event name rather than on human-readable titles or messages — titles are for people and may be reworded, codes are for machines and are held stable.