IPA-120: Versioning
API producers should avoid incrementing the API version where possible, prioritizing supporting the current API version unless absolutely necessary. This philosophy reduces exposing clients to the friction of migrating versions, and multiple versions complicate maintenance, testing, and documentation.
Guidance
An API producer should consider whether a change warrants a new version or can instead be made in a backward-compatible fashion, referring to backward compatibility (IPA-116) before versioning the API.
paths:
/users/{userId}:
get:
operationId: getUser
responses:
"200":
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
email:
type: stringWhy:Adding the optional
emailfield to an existing response is additive and backward compatible, so the change lands in the current version instead of forcing a new one.paths:
/v2/users/{userId}:
get:
operationId: getUserV2
responses:
"200":
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
email:
type: stringWhy:A whole new version is spun up to carry one additive field that the current version could already accept, splitting clients across versions for no compatibility reason.
Identify the change under review and the version it targets — a new version path/prefix, a new version-tagged operation, or a header-selected version.
Classify the change against IPA-116: adding optional fields, new optional parameters, or new operations is additive; removing or renaming fields/paths, tightening types, or changing required-ness is breaking.
Confirm that any change introducing a new version is one that cannot be expressed additively in the current version.
Report any new version whose change is additive and could have stayed in the current version.
An API producer should not version the API when the desired functionality can be achieved in a backward-compatible fashion.
paths:
/orders/{orderId}:
get:
operationId: getOrder
parameters:
- name: includeItems
in: query
required: false
schema:
type: boolean
responses:
"200":
description: An order.Why:The new behavior is opt-in through an optional query parameter on the existing operation, so the functionality ships without a version bump.
paths:
/orders/{orderId}:
get:
operationId: getOrder
responses:
"200":
description: An order.
/v2/orders/{orderId}:
get:
operationId: getOrderV2
parameters:
- name: includeItems
in: query
required: false
schema:
type: boolean
responses:
"200":
description: An order with items.Why:The same opt-in behavior is delivered by duplicating the operation under a new version, even though an optional parameter on the existing operation would have been backward compatible.
For each newly introduced version, list the functionality it adds relative to the prior version.
For each added capability, determine whether it could be expressed in the current version through additive means: an optional parameter, an optional response field, or a new operation.
Flag any version whose entire delta is achievable backward-compatibly in the current version.
An API producer should consider introducing a new endpoint alongside the existing one, in lieu of a new version.
paths:
/projects/{projectId}/reports:
get:
operationId: listReports
/projects/{projectId}/reports/summary:
get:
operationId: getReportSummaryWhy:The new summarized behavior is exposed as an additional endpoint next to the existing collection, so neither the operation nor the version has to change.
paths:
/projects/{projectId}/reports:
get:
operationId: listReports
/v2/projects/{projectId}/reports:
get:
operationId: listReportsV2Why:A distinct capability is delivered by re-versioning the same resource rather than adding a sibling endpoint, which would have left existing consumers untouched.
For each new version, identify the resources or operations it introduces.
Determine whether each new capability represents distinct functionality that could live at its own path alongside the existing endpoints.
Flag versions whose additions are new capabilities that a sibling endpoint in the current version could have carried.
An API producer should avoid versioning an API solely to rename existing fields or paths.
paths:
/invoices/{invoiceId}:
get:
operationId: getInvoice
responses:
"200":
content:
application/json:
schema:
type: object
properties:
total:
type: number
amount:
type: number
deprecated: trueWhy:A clearer name is added while the old field is kept and marked deprecated, so the rename happens without a version bump and without breaking existing clients.
paths:
/v2/invoices/{invoiceId}:
get:
operationId: getInvoiceV2
responses:
"200":
content:
application/json:
schema:
type: object
properties:
total:
type: numberWhy:A new version exists only to rename
amounttototal, which forces every client to migrate for a purely cosmetic change.For each new version, diff its fields and paths against the prior version.
Determine whether the only differences are renamed fields or paths with no change in behavior, type, or semantics.
Flag any version whose sole change is a rename of existing fields or paths.
An API producer may coordinate to sunset old versions faster than the default timeline of one year.
An API producer must coordinate with clients to transition to new versions to avoid impact.
paths:
/v1/users/{userId}:
get:
operationId: getUserV1
deprecated: true
responses:
"200":
headers:
Sunset:
schema:
type: string
format: date
description: A user. This version is deprecated; migrate to v2.
/v2/users/{userId}:
get:
operationId: getUserV2
responses:
"200":
description: A user.Why:The superseded version stays available, is marked
deprecated, and advertises aSunsetdate, giving consumers a signalled window to move before the old version is withdrawn.paths:
/v2/users/{userId}:
get:
operationId: getUserV2
responses:
"200":
description: A user.Why:The previous version was removed outright with no deprecation marker or sunset signal, so consumers still on it break the moment it disappears.
Compare the spec against the previously published version to find any operations or versions that were removed or replaced.
For each superseded version, confirm the prior version remains available during a transition window rather than being dropped at once.
Confirm the superseded operations are marked
deprecatedand advertise a sunset signal (such as aSunsetheader or a deprecation date in the description).Inspect release notes, changelogs, or client-communication records to confirm consumers were notified ahead of the transition.
Report any version transition that removes a prior version without a deprecation period, sunset signal, and evidence of client coordination.