Appearance
API Versioning Policy ​
Status: Accepted Work item: AB#4334 Scope: Heritage Community Hub API (apps/api)
Purpose ​
Define how the Heritage Community Hub API evolves over time without breaking existing clients (iOS, Android, web).
Current state ​
All API routes are served under /api/v1/.... There is no v2 today. v1 is the current, stable version and remains the default for all clients.
Versioning scheme ​
- URL-based versioning is canonical. The version segment in the URL (
/api/v1/...) is the single source of truth for which contract a client is calling. - Header-based negotiation is optional and informational only. Clients MAY send
Accept-Version: v1for clarity in logs and traces, but the URL determines the response contract. If the header disagrees with the URL, the URL wins. - Version numbers are major-only (
v1,v2,v3). We do not version minor or patch increments — those are handled by additive, backwards-compatible changes within the existing major version.
What counts as a breaking change ​
A change that requires a new major version (v2):
- Removing a field from a response body
- Renaming a field in a request or response body
- Changing the type or shape of an existing field (e.g.,
string→object,array→ scalar) - Removing an endpoint or HTTP method
- Changing authentication requirements on an existing endpoint (e.g., adding a new required scope or role)
- Changing existing error codes, error response shapes, or HTTP status codes returned for the same condition
- Making a previously optional request field required
- Tightening validation in a way that rejects payloads previously accepted
What is NOT a breaking change ​
Additive changes that ship under the existing major version without bumping:
- Adding a new endpoint
- Adding a new optional field to a request body
- Adding a new field to a response body (clients must ignore unknown fields)
- Adding new optional query parameters
- Adding new optional headers
- Bug fixes that bring behavior in line with the documented contract
- Performance improvements that do not change the contract
- Loosening validation to accept additional valid inputs
v2 promotion path ​
When a breaking change is required:
- Add
v2alongsidev1. New routes are mounted at/api/v2/....v1continues to serve its existing contract unchanged. - Deprecate
v1formally. Allv1responses begin returning theDeprecationheader with the sunset date in HTTP-date format:Deprecation: Sun, 24 Dec 2026 00:00:00 GMT Sunset: Sun, 24 Dec 2026 00:00:00 GMT Link: </api/v2/...>; rel="successor-version" - Notify clients. Minimum 6 months between the
Deprecationheader appearing andv1removal. Communicate via release notes and changelog (member-facing) plus direct outreach to known integrators. - Monitor migration. Track
v1vsv2request volume by route. Do not removev1untilv2is stable in production ANDv1traffic from active clients has stopped. - Remove
v1. Only after the sunset date AND zero active-client traffic.v1URLs then return410 Gonefor one further release before the routes are deleted entirely.
Client guidance ​
- Always pin to a specific major version in the URL. Never call
/api/...without a version segment. - Treat unknown fields in responses as optional — do not fail on additive changes.
- Watch for the
Deprecationresponse header and plan migration well before theSunsetdate.
Internal guidance for contributors ​
- Default to additive. Most API changes can ship under
v1without a new version. - If a change feels like it might be breaking, treat it as breaking and discuss in PR review before shipping.
- Document every new version in
docs/internal/design/api-contracts.mdwith the diff from the previous version. - Never modify the contract of an existing version after it has shipped to production.