API Versioning, Revisions and Lifecycle
Versions vs Revisions
Azure API Management distinguishes between two types of API changes:
Revisions
Non-breaking changes — bug fixes, policy updates
VisibilityHidden until made current
URLSame URL (optional
;rev=N for testing)Breaking changesNo
Parallel accessOnly current revision is live
Versions
Breaking changes — new schema, removed fields
VisibilityPublished as separate API
URLDifferent URL path, header, or query param
Breaking changesYes
Parallel accessMultiple versions live simultaneously
Microsoft Reference: Versions and revisions
Revisions
Creating a Revision
# Create a new revision
az apim api revision create \
--resource-group rg-integration-prod \
--service-name apim-enterprise-prod \
--api-id orders-api \
--api-revision 2 \
--api-revision-description "Add pagination support to GET /orders"
Testing a Revision
Access a specific revision by appending ;rev=N to the API path:
# Test revision 2 (not yet live)
curl "https://apim-enterprise-prod.azure-api.net/orders;rev=2/orders" \
-H "Ocp-Apim-Subscription-Key: your-key"
Making a Revision Current
# Make revision 2 the current (live) version
az apim api release create \
--resource-group rg-integration-prod \
--service-name apim-enterprise-prod \
--api-id orders-api \
--api-revision 2 \
--notes "Released pagination support"
Revision Workflow
1. Create revision 2 from current revision
2. Make changes to revision 2 (policies, operations, schemas)
3. Test revision 2 using ;rev=2 in the URL
4. Create a release to make revision 2 current
5. Previous revision remains accessible for rollback
Bicep Configuration
resource ordersApiRevision 'Microsoft.ApiManagement/service/apis@2023-05-01-preview' = {
parent: apim
name: 'orders-api;rev=2'
properties: {
displayName: 'Orders API'
path: 'orders'
protocols: ['https']
apiRevision: '2'
apiRevisionDescription: 'Add pagination support'
subscriptionRequired: true
sourceApiId: ordersApi.id
}
}
Versions
Versioning Schemes
| Scheme | Example | Use Case |
|---|---|---|
| URL Path | /v1/orders, /v2/orders |
Most common, explicit |
| Query String | /orders?api-version=2024-01-01 |
Azure-style, flexible |
| Header | Api-Version: v2 |
Clean URLs, more complex for consumers |
Microsoft Reference: API versioning
Creating a Version Set
resource versionSet 'Microsoft.ApiManagement/service/apiVersionSets@2023-05-01-preview' = {
parent: apim
name: 'orders-api-version-set'
properties: {
displayName: 'Orders API'
versioningScheme: 'Segment' // URL path segment
description: 'Version set for the Orders API'
}
}
resource ordersApiV1 'Microsoft.ApiManagement/service/apis@2023-05-01-preview' = {
parent: apim
name: 'orders-api-v1'
properties: {
displayName: 'Orders API v1'
path: 'orders'
apiVersion: 'v1'
apiVersionSetId: versionSet.id
protocols: ['https']
subscriptionRequired: true
format: 'openapi+json'
value: loadTextContent('api-specs/orders-v1.json')
}
}
resource ordersApiV2 'Microsoft.ApiManagement/service/apis@2023-05-01-preview' = {
parent: apim
name: 'orders-api-v2'
properties: {
displayName: 'Orders API v2'
path: 'orders'
apiVersion: 'v2'
apiVersionSetId: versionSet.id
protocols: ['https']
subscriptionRequired: true
format: 'openapi+json'
value: loadTextContent('api-specs/orders-v2.json')
}
}
Resulting URLs
https://apim-enterprise-prod.azure-api.net/orders/v1/orders → v1 backend
https://apim-enterprise-prod.azure-api.net/orders/v2/orders → v2 backend
API Lifecycle Management
Lifecycle Stages
Draft → Published → Deprecated → Retired
| Stage | Description | Consumer Impact |
|---|---|---|
| Draft | Under development, not visible | No access |
| Published | Active and available | Full access |
| Deprecated | Still available but discouraged | Sunset header returned |
| Retired | Removed from service | 410 Gone response |
Deprecation Policy
Add sunset headers to deprecated API versions:
<outbound>
<set-header name="Sunset" exists-action="override">
<value>Sat, 01 Jun 2026 00:00:00 GMT</value>
</set-header>
<set-header name="Deprecation" exists-action="override">
<value>true</value>
</set-header>
<set-header name="Link" exists-action="override">
<value><https://api.example.com/v2/docs>; rel="successor-version"</value>
</set-header>
</outbound>
Retirement Policy (Return 410 Gone)
<inbound>
<return-response>
<set-status code="410" reason="Gone" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>{
"error": "API_RETIRED",
"message": "This API version has been retired. Please migrate to v2.",
"migrationGuide": "https://docs.example.com/migration/v1-to-v2",
"newEndpoint": "https://api.example.com/v2"
}</set-body>
</return-response>
</inbound>
API Governance
Products for Access Control
Use Products to control which API versions are available to which consumers:
resource internalProduct 'Microsoft.ApiManagement/service/products@2023-05-01-preview' = {
parent: apim
name: 'internal-apis'
properties: {
displayName: 'Internal APIs'
description: 'APIs for internal services'
subscriptionRequired: true
approvalRequired: false
state: 'published'
}
}
resource externalProduct 'Microsoft.ApiManagement/service/products@2023-05-01-preview' = {
parent: apim
name: 'external-apis'
properties: {
displayName: 'External Partner APIs'
description: 'APIs for external partners'
subscriptionRequired: true
approvalRequired: true // Manual approval required
state: 'published'
terms: 'By subscribing, you agree to our API Terms of Service.'
}
}
API Change Log
Maintain a change log for consumers using the revision description:
Revision 5 (2026-03-14): Added pagination support to GET /orders
Revision 4 (2026-02-28): Fixed response schema for GET /orders/{id}
Revision 3 (2026-02-15): Added rate limiting policy (100 req/min)
Revision 2 (2026-02-01): Added X-Correlation-Id header to responses
Revision 1 (2026-01-15): Initial release
OpenAPI Specification Management
Exporting API Definitions
# Export OpenAPI 3.0 specification
az apim api export \
--resource-group rg-integration-prod \
--service-name apim-enterprise-prod \
--api-id orders-api \
--export-format openapi-link
# Export WSDL
az apim api export \
--resource-group rg-integration-prod \
--service-name apim-enterprise-prod \
--api-id legacy-soap-api \
--export-format wsdl-link
API-First Design
1. Design API in OpenAPI (Swagger Editor / Stoplight / SwaggerHub)
2. Review with stakeholders
3. Import to APIM as a new version
4. Apply policies (security, rate limiting, transformation)
5. Publish to Developer Portal
6. Generate client SDKs from OpenAPI spec
Microsoft Reference: API design best practices
CI/CD for API Lifecycle
Azure DevOps Pipeline for API Deployment
trigger:
branches:
include:
- main
paths:
include:
- apis/*
variables:
- group: apim-settings
stages:
- stage: ValidateAPIs
jobs:
- job: Validate
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '3.x'
- script: |
pip install openapi-spec-validator
python -c "from openapi_spec_validator import validate_spec; import json; validate_spec(json.load(open('apis/orders-v2.json')))"
displayName: 'Validate OpenAPI Spec'
- stage: DeployAPIs
dependsOn: ValidateAPIs
jobs:
- deployment: DeployToAPIM
environment: 'apim-production'
strategy:
runOnce:
deploy:
steps:
- checkout: self
- task: AzureCLI@2
displayName: 'Import API to APIM'
inputs:
azureSubscription: 'prod-service-connection'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az apim api import \
--resource-group $(resourceGroup) \
--service-name $(apimName) \
--api-id orders-api-v2 \
--path orders \
--api-version v2 \
--api-version-set-id orders-api-version-set \
--specification-format OpenApiJson \
--specification-path apis/orders-v2.json \
--display-name "Orders API v2"
Best Practices
- Use URL path versioning for public APIs — it's the most explicit and discoverable
- Create revisions for non-breaking changes — avoid creating unnecessary versions
- Document all changes with revision descriptions
- Set sunset dates well in advance (minimum 6 months for external APIs)
- Use Products to control version access per consumer group
- Validate OpenAPI specs in CI/CD before importing to APIM
- Maintain backward compatibility within a version — use revisions for fixes
- Monitor version usage to identify when old versions can be retired
- Provide migration guides when deprecating versions
- Use semantic versioning (v1, v2) for clarity