All topics
API versioning best practices

API versioning best practices

Release breaking changes without disrupting existing clients.

Problem statement

It's typical for an API product to evolve over time as new features are added, existing features are modified, bugs are fixed, and occasionally existing features are retired.

In most cases it is best practice to make changes to an API in a backwards-compatible way, to not disrupt existing customer integrations. Sometimes making a breaking change is unavoidable. In these circumstances, it is desirable to release the change to a controlled subset of customers, without impacting the rest.

Success criteria

Versioning helps improve trust and confidence in an API by avoiding breaking client integrations.

Of course, the purpose of each new version is to deliver greater value to customers. Metrics should measure adoption to assess whether the benefit provided by a new version outweighs the migration cost for consumers.

GoalSignalMetric
Improve trustPass rateReduce the number of invalid requests that were previously successful to 0.
Increase product usageAdoption rateThe proportion of clients using the new version is above X% after Y weeks/months since release.

Product requirements

API versioning provides a mechanism to deliver previous and new functionality and behavior to different customers simultaneously.

Strictly speaking, the API's version only needs to change when a breaking change is introduced. For non-breaking changes, the API can be updated without increasing the version. This approach keeps the API version relatively stable.

The downside of only increasing the API's version for breaking changes is that it makes communicating other enhancements less clear as they are no longer tied to new version numbers. This can be mitigated by using semantic versioning, where only the major version number needs to be specified, but the changelog can describe the full version number.

User stories

An API contract is a promise, which developers expect to be upheld. There are a number of valid strategies for upholding this promise:

  1. Never change the API contract for a given version. Always increment the API version for each change to the contract.
  2. Only release backwards-compatible changes to a given API version. Only increment the API version for breaking changes.
  3. If using Semantic Versioning, advise developers that changes to minor and patch versions will always be backwards compatible, and that they can pin their integration to the major version only.

Major version updates should always be opt-in. Allow the client to specify the API version that their integration uses, either through internal configuration or through the API request itself.

If the client's version is determined from an internal configuration, your customer will have to coordinate with you to perform migrations. This can be costly and time consuming for both the API consumer and provider. Prefer to provide a self-serve mechanism for specifying the API version.

Allowing the client to specify which version of the API to use on a per-request basis gives the client the most amount of flexiblity and control:

  1. The client can opt-in to new versions at will.
  2. The client can specify different versions in different environments. For example, the client can specify version 1 in their Production environment, and version 2 in their QA environment.
  3. The client can migrate a portion of their integration to a new version, while keeping the rest of the integration the same.

This approach can be combined with a default version configuration, such that the per-request version acts as an optional override.

When returning errors due to version mismatch, it is a good idea to include links to the any relevant versioning policies, changelogs, and migration guides in the human-readable portion of the error response.

Once an API is deprecated, existing clients should be able to continue access it, but new clients should not.

You can store the minimum supported version per API client, so that client credentials issued after a certain date cannot be used to access APIs that were deprecated on that date.

Any mechanism that allows the client to specify which version of an API to use needs to consider whether clients should opt in or opt out of receiving security updates.

If your API uses Semantic Versioning, an opt-out approach could be to allow clients to specify only the major and minor version to use, without a patch version, i.e. major.minor. This ensures that when you release a security update as a patch, all customers will receive it automatically. Customers can opt out of this behavior by specifying the full semantic version, i.e. major.minor.patch.

If your reference documentation is backed by OpenAPI, Operation and Paramter objects support a deprecated field to declare them as deprecated.

If a release that doesn't include any breaking changes, the developer may decide to migrate to it immediately since it is a lower risk.

All APIs should have a deprecation policy, which stipulates that deprecated APIs will continue to be supported for a period of time, such as 12 months.

During the deprecation period, notify customers who haven't migrated on a periodic basis with increasing frequency.

Customers may need to incorporate the effort in their overall backlog, staff on-call resources and notify customers. Sometimes a customer cannot prioritize the appropriate resources before the sunset date. Depending on the relationship you have with your customers, you may need to be prepared to extend the migration deadline for the last few customers.

Explore design patterns

Semantic versioning

Distinguish between major, minor and patch versions.

Date-based versioning

Easily understand when a version was released.

URI versioning

Clearly segment different versions of the API.

Header versioning

Enable versioning on a per-request basis.

API examples

APIFormat How specified
Salesforce Platform APIsXX.XBase URI, https://MyDomainName.my.salesforce.com/services/data/vXX.X/resource/
Notion APIYYYY-MM-DDNotion-Version header
WhatsApp Cloud APIv17.0Base URI, https://graph.facebook.com/v17.0
MicrosoftGraphv1.0 or betaBase URI, https://graph.microsoft.com/{version}
PayPal APIsv2Base URI, https://api-m.sandbox.paypal.com/v2
Stripe APIYYYY-MM-DDStripe-Version header
Razorpay APIsv1Base URI, https://api.razorpay.com/v1
MongoDB Data APIv1 or betaBase URI, https://data.mongodb-api.com/app/<Data API App ID>/endpoint/data/v1
Zoho CRM REST APIsv4Base URI, https://www.zohoapis.com/crm/v4
Datadog REST APIv1Base URI, https://api.datadoghq.com/api/v1
Meraki Dashboard APIv1Base URI, https://api.meraki.com/api/v1
Pipedrive APIv1Base URI, https://{COMPANYDOMAIN}.pipedrive.com/api/v1
Twilio Messaging / SMS APIYYYY-MM-DDBase URI,https://api.twilio.com/2010-04-01
GitHub APIYYYY-MM-DDX-GitHub-Api-Version header

Further reading

  • https://restfulapi.net/versioning/
  • https://www.infoq.com/articles/roy-fielding-on-versioning/
  • https://zuplo.com/blog/2022/05/17/how-to-version-an-api
  • https://labs.qandidate.com/blog/2014/10/16/using-the-accept-header-to-version-your-api/
  • https://cloud.google.com/blog/products/api-management/api-design-which-version-of-versioning-is-right-for-you

Was this page helpful?

Made by Criteria.