Versioning

API Versioning Best Practices for Secure Changes

Published: 19 September 2026

A new version is a security change whenever clients, routes or permission rules move with it.

Define what a version promises

API versioning best practices begin with a clear compatibility policy. State whether a version label identifies a public contract, an implementation release, or both. Adding an optional response field may be compatible for tolerant clients but can still break consumers that reject unknown fields. Changing a field's meaning, permission requirement, pagination default, or error shape can be breaking even if the URL and schema type stay the same.

Choose a version mechanism clients can handle consistently: path, header, media type, or another documented approach. Avoid mixing mechanisms without a transition plan. Keep a contract for every supported version and test it against the matching deployment. An OpenAPI file that silently describes only the newest behaviour leaves older clients and security reviewers guessing.

Treat authorization as part of compatibility

A v2 route may require a new scope while v1 still accepts a broad old token. That gap can keep sensitive data reachable long after the new policy is deployed. Build a version-by-role and tenant test matrix for high-risk operations. Test direct calls to deprecated routes, not just clients that have migrated. A new version must not create an alternate path around object-level checks.

When an operation changes ownership or field visibility, describe the new rule and verify old behaviour is either still intentionally supported or removed. Avoid returning hidden fields to v1 simply to preserve a loose response contract. If a security fix must break compatibility, communicate it clearly and provide a migration path rather than retaining an unsafe endpoint indefinitely.

Detect breaking changes before release

Compare the proposed OpenAPI contract with the currently supported one. Review removed routes, renamed fields, tighter input bounds, changed response codes, and new authentication requirements. Automated diff tools help surface changes, but humans must decide whether a meaning or security promise changed. Add consumer contract tests for important integrations and run them against the candidate service.

Document changes in a concise changelog with examples. A client needs to know how to move from an old request to a new one, how errors differ, and whether data access changes. Test SDKs and generated clients when schema shape changes. Keep the exact contract artifact used for each release so an incident review can reconstruct what was promised at the time.

Deprecate with observable milestones

Announce a deprecation date, a migration guide, and a planned end of service. Where applicable, use a Sunset header to communicate the expected retirement of a resource. Do not assume every client will read a header; notify known integrators through their normal support channel as well. Monitor usage by client and route without logging raw credentials or personal payloads.

Before removal, identify clients still relying on the old version and resolve blockers. Set a rollback decision before switching traffic off. After retirement, remove route mappings, credentials, documentation, and old infrastructure permissions. Verify that the endpoint is unreachable from the public network and internal paths. A route left in a gateway can become a zombie API even if it no longer appears in the latest specification.

Use static and live evidence together

APISAST can flag missing versioning signals or deprecated operations without sunset information in an OpenAPI or Swagger contract. It cannot determine whether a specific client will break or whether the old route still runs. Pair the scan with contract diffs, client tests, traffic measurement, and route inventory comparison.

Review every supported version for authentication, error responses, request limits, and pagination rather than assuming v1 inherits v2 protections. Keep one owner for each version and a documented support window. Versioning is an operational commitment: the secure outcome comes from tracking every live route through release, migration, and removal.

Example: splitting a customer record

Suppose v1 returns a customer object with name, address, and billing status. In v2, billing status moves to a privileged operation. The change is not complete if v1 still exposes the field to every authenticated user. Decide whether v1 must be patched, access narrowed, or the route retired early. Update both contracts, test low-privilege responses on both versions, and notify clients that relied on the old field.

Also check caching and generated SDKs. A shared cache key that ignores version or identity can return a v1 representation to a v2 caller. A generated client may continue requesting the old route even after the application code migrates. Use logs to identify those clients, but avoid storing private response bodies merely to measure usage.

Write a retirement checklist

Record the owner, announcement date, known clients, support end, migration example, traffic threshold, and rollback trigger. Before the retirement date, verify that the new route supports the necessary use cases and that clients have test credentials. After the date, remove the route from gateways, service deployments, internal DNS, and test fixtures where appropriate.

Keep an archive of the old contract for incident analysis, marked as retired so new clients do not adopt it. Watch 404 or 410 traffic briefly to catch missed integrations, and provide a useful support path. A secure versioning programme ends only when old permissions and infrastructure are actually removed, not when a blog post announces the new version. During a long overlap, scan and test both versions on every release. Check whether a vulnerability fixed in the newest route still exists in the older implementation. Give each supported version an owner who can make that fix and a date when support will end. Track client migration against that date so the old route does not become indefinite technical debt.

Continue the work

Use these guides to put the checks into your API review process:

Primary reference: RFC 8594 Sunset HTTP Header.

APISAST reviews OpenAPI and Swagger contracts for documented design signals. Confirm authorization, enforcement, performance, and abuse controls against a running service.

More API security guides