Table of Contents

    versioning

    API DESIGN & SERVICE CONTRACTS

    Versioning

    Learn how to evolve REST, GraphQL, and gRPC service contracts without unexpectedly breaking existing clients through compatibility rules, version-selection strategies, deprecation policies, migration plans, and automated contract testing.

    Introduction

    APIs evolve as products gain features, business rules change, security requirements become stricter, and implementation constraints are discovered. However, clients can depend on existing fields, status codes, validation rules, ordering, and behavioural details.

    API versioning is the practice of managing contract changes so that clients can understand which API behaviour they are using and migrate between incompatible contracts in a controlled way.

    Versioning helps manage changes to:

    • Resource representations
    • Request and response fields
    • Endpoint paths
    • Data types and formats
    • Validation rules
    • Error responses
    • Pagination behaviour
    • Authentication requirements
    • Rate-limit semantics
    • GraphQL schemas
    • Protocol Buffer messages
    • Business behaviour

    Core idea: Versioning is not a substitute for backward compatibility. Prefer compatible evolution within an existing version, and introduce a new major contract only when clients cannot continue safely without changing their implementation.

    In your System Design curriculum, Versioning is Topic 4.6 under API Design & Service Contracts. It follows pagination and precedes idempotency, authentication versus authorization, and rate-limit semantics.

    Prerequisites

    # Prerequisite Why It Is Needed
    1 REST REST contracts can use URI, field, media-type, or other version-selection strategies.
    2 RPC and gRPC Typed service contracts require strict schema-compatibility rules.
    3 GraphQL GraphQL commonly evolves one schema through additive changes and deprecation.
    4 Resource modeling Changing resource identity, fields, relationships, or lifecycle can affect clients.
    5 Pagination Ordering, cursor formats, and page metadata are part of the API contract.
    6 Automated testing Compatibility should be verified before a changed contract is released.

    What Is an API Version?

    An API version identifies a defined set of externally observable contract behaviour.

    A version can cover:

    • Available operations
    • Resource and method names
    • Request schemas
    • Response schemas
    • Field semantics
    • Error contracts
    • Authentication requirements
    • Pagination and ordering
    • Retry and idempotency behaviour
    • Compatibility guarantees
    Contract Evolution
    propose change → classify compatibility → test existing clients → version if required → document migration → monitor adoption

    Versioning vs Backward Compatibility

    Concept Meaning
    API versioning Identifies and manages different forms of an API contract
    Backward compatibility Allows existing clients to continue working after a service change
    Deprecation Communicates that a supported contract element is planned for replacement or removal
    Sunsetting Ends support for a version or contract element according to a communicated policy
    Migration Moves clients from one supported contract to another

    Good compatibility discipline reduces how often a new major API version is necessary.

    Backward-compatible Changes

    A backward-compatible change allows supported existing clients to continue using the API without required code changes.

    Commonly compatible changes can include:

    • Adding a new optional request field
    • Adding a new response field that clients are expected to ignore
    • Adding a new endpoint
    • Adding a new optional query parameter
    • Adding a new GraphQL type or field
    • Adding a new Protocol Buffer field with a new field number
    • Adding a new optional capability
    • Improving performance without changing semantics

    Additive REST Change

    Existing representation

    {
      "id": "cus_42",
      "displayName": "Example Customer",
      "status": "active"
    }

    Compatible extension

    {
      "id": "cus_42",
      "displayName": "Example Customer",
      "status": "active",
      "preferredLanguage": "en"
    }

    This addition is compatible only when existing clients tolerate unknown response fields as required by the API's compatibility policy.

    Breaking Changes

    A breaking change requires one or more existing clients to modify their implementation to continue working correctly.

    Examples include:

    • Removing a field
    • Renaming a field
    • Changing a field's type
    • Changing a field's meaning or unit
    • Changing an optional field to required
    • Tightening validation rules
    • Removing an endpoint or method
    • Changing an error-response structure
    • Changing default pagination ordering
    • Reducing an established maximum page size
    • Changing authentication requirements unexpectedly
    • Changing retry or idempotency behaviour

    Type Change

    Existing contract
    {
      "customerId": "42"
    }
    Breaking replacement
    {
      "customerId": 42
    }

    Even when both values represent the same identifier, changing from a string to a number can break parsing, generated clients, validation, and stored integrations.

    Behavioural Breaking Changes

    A change can preserve the schema and still break clients by changing behaviour.

    Pagination Example

    Existing ordering:
    
    createdAt ascending
    
    
    Changed ordering:
    
    createdAt descending
    
    
    Schema:
    
    Unchanged
    
    
    Client impact:
    
    Items appear in a different sequence.
    Stored cursors or synchronization logic
    can become invalid.

    Other behavioural changes can include:

    • Changing rounding behaviour
    • Changing time-zone interpretation
    • Changing null to an empty collection
    • Changing deletion from physical deletion to archival
    • Changing which errors are retryable
    • Changing the meaning of a status value
    • Changing consistency guarantees

    Review rule: Compatibility reviews must examine semantics and behaviour, not only JSON schemas or method signatures.

    Major, Minor, and Patch Versions

    Some API programs use semantic-style version numbers to classify releases.

    Component General Purpose Example
    Major Identifies an incompatible contract generation 2.0.0
    Minor Identifies compatible added functionality 1.4.0
    Patch Identifies compatible corrections 1.4.2

    The externally selected API version does not always need to expose the full internal release number. For example, clients can select v1 while documentation and deployments track 1.4.2.

    URI Path Versioning

    Path versioning places the major version in the URI.

    GET /v1/customers/cus_42 HTTP/1.1
    Host: api.example.com
    GET /v2/customers/cus_42 HTTP/1.1
    Host: api.example.com

    Benefits

    • The selected version is visible
    • Requests are easy to test
    • Routing rules are straightforward
    • Documentation can be separated clearly
    • Different major versions can run concurrently

    Considerations

    • Resource URIs differ between major versions
    • Clients must change URLs during migration
    • Shared implementation can become duplicated
    • Too many active versions increase operational complexity

    Header Versioning

    Header versioning places the version in a request field.

    GET /customers/cus_42 HTTP/1.1
    Host: api.example.com
    API-Version: 2

    A custom header can keep resource paths stable, but the selected contract is less visible in ordinary links and browser navigation.

    The contract must define:

    • The exact header name
    • Supported values
    • Behaviour when the header is missing
    • Behaviour for unsupported versions
    • Cache-key behaviour
    • Proxy and gateway forwarding

    Media-type Versioning

    A representation version can be selected through media-type negotiation.

    GET /customers/cus_42 HTTP/1.1
    Host: api.example.com
    Accept: application/vnd.example.customer.v2+json
    HTTP/1.1 200 OK
    Content-Type: application/vnd.example.customer.v2+json

    This approach can express representation-level versions while preserving the resource URI. It requires consistent media-type negotiation, documentation, caching, and tooling support.

    Query-parameter Versioning

    GET /customers/cus_42?apiVersion=2 HTTP/1.1
    Host: api.example.com

    Query-parameter versioning is visible and simple to test. However, version selection becomes mixed with ordinary resource-query parameters and must be handled consistently by caches, gateways, documentation, and generated clients.

    Date-based Versioning

    Some services identify a contract using a date.

    GET /customers/cus_42 HTTP/1.1
    Host: api.example.com
    API-Version: 2026-09-22

    A date-based contract must define whether the date refers to a release, a compatibility snapshot, or another API behaviour set. A date alone does not explain whether a release contains breaking changes.

    Comparing Version-selection Strategies

    Strategy Example Main Benefit Main Consideration
    URI path /v2/orders Highly visible and easy to route Changes public resource URLs
    Custom header API-Version: 2 Keeps URLs stable Version is less visible
    Media type application/vnd.example.v2+json Supports representation negotiation More complex for clients and tooling
    Query parameter ?apiVersion=2 Simple to test Mixes contract selection with resource parameters
    Date based 2026-09-22 Identifies a contract snapshot Compatibility meaning requires separate documentation

    Selection rule: Choose one clear version-selection strategy based on client usability, routing, caching, documentation, and lifecycle needs. Apply it consistently across the API.

    Missing Version Behaviour

    The API should define what happens when a client does not select a version.

    Possible policies include:

    • Require an explicit version
    • Use a documented stable default
    • Use the version encoded in the URI
    • Reject requests without supported version information
    Unsafe default
    Missing version means:
    
    Use whichever version was deployed most recently.
    Predictable contract
    Missing version means:
    
    Use documented version 1
    or reject the request.
    
    The behaviour does not change silently
    when version 2 is deployed.

    PHP Path-version Routing

    <?php
    
    declare(strict_types=1);
    
    $path =
        parse_url(
            $_SERVER['REQUEST_URI'],
            PHP_URL_PATH
        );
    
    if (!is_string($path)) {
        http_response_code(400);
    
        exit(
            'Invalid request URI.'
        );
    }
    
    $segments =
        array_values(
            array_filter(
                explode(
                    '/',
                    trim($path, '/')
                ),
                static fn (
                    string $segment
                ): bool => $segment !== ''
            )
        );
    
    $version =
        $segments[0] ?? null;
    
    $supportedVersions = [
        'v1',
        'v2'
    ];
    
    if (!in_array(
            $version,
            $supportedVersions,
            true
        )) {
    
        http_response_code(404);
    
        header(
            'Content-Type: application/problem+json'
        );
    
        echo json_encode(
            [
                'type' =>
                    'unsupported-api-version',
                'title' =>
                    'Unsupported API version',
                'status' => 404,
                'detail' =>
                    'The requested API version is not supported.'
            ],
            JSON_THROW_ON_ERROR
        );
    
        exit;
    }
    
    $resource =
        $segments[1] ?? null;
    
    if ($resource !== 'customers') {
        http_response_code(404);
    
        exit;
    }
    
    require $version === 'v1'
        ? 'controllers/v1/CustomerController.php'
        : 'controllers/v2/CustomerController.php';

    A production router should normalize paths, authorize requests, validate method support, apply observability, and avoid duplicating unchanged business logic between versioned controllers.

    PHP Header-version Selection

    <?php
    
    declare(strict_types=1);
    
    $requestedVersion =
        $_SERVER['HTTP_API_VERSION'] ??
        null;
    
    if ($requestedVersion === null) {
        http_response_code(400);
    
        header(
            'Content-Type: application/problem+json'
        );
    
        echo json_encode(
            [
                'type' =>
                    'missing-api-version',
                'title' =>
                    'API version is required',
                'status' => 400
            ],
            JSON_THROW_ON_ERROR
        );
    
        exit;
    }
    
    $supportedVersions = [
        '1',
        '2'
    ];
    
    if (!in_array(
            $requestedVersion,
            $supportedVersions,
            true
        )) {
        http_response_code(400);
    
        header(
            'Content-Type: application/problem+json'
        );
    
        echo json_encode(
            [
                'type' =>
                    'unsupported-api-version',
                'title' =>
                    'Unsupported API version',
                'status' => 400
            ],
            JSON_THROW_ON_ERROR
        );
    
        exit;
    }

    Separate Contract from Business Logic

    Supporting two versions should not require copying the complete application implementation.

    Version 1 Controller
            |
            | Maps v1 request to domain command
            v
    Shared Application Service
            |
            v
    Domain and Persistence Logic
            |
            v
    Version 1 response mapping
    
    
    Version 2 Controller
            |
            | Maps v2 request to domain command
            v
    Same Shared Application Service
            |
            v
    Domain and Persistence Logic
            |
            v
    Version 2 response mapping

    Version-specific adapters can translate between public contracts and shared internal domain operations.

    GraphQL Versioning

    GraphQL commonly evolves one schema through additive changes and field deprecation rather than introducing a new version for every change.

    Additive Field

    type Customer {
      id: ID!
      displayName: String!
      status: CustomerStatus!
      preferredLanguage: String
    }

    Deprecated Field

    type Customer {
      id: ID!
    
      name: String
        @deprecated(
          reason: "Use displayName."
        )
    
      displayName: String!
    }

    A GraphQL deprecation process should include:

    • A clear reason
    • A supported replacement
    • Operation-usage monitoring
    • Client communication
    • A documented removal policy

    GraphQL Breaking Changes

    • Removing a field
    • Renaming a field
    • Changing a field's output type incompatibly
    • Making a nullable output field non-null without a reliable guarantee
    • Adding a required input field without a default
    • Removing an enum value
    • Changing resolver semantics

    gRPC and Protocol Buffer Versioning

    Protocol Buffer contracts use stable numeric field identifiers. Compatibility depends on preserving field numbers and compatible wire meanings.

    Additive Change

    message Customer {
      int64 id = 1;
      string display_name = 2;
      CustomerStatus status = 3;
    
      string preferred_language = 4;
    }

    Reserve Removed Fields

    message Customer {
      int64 id = 1;
      string display_name = 2;
    
      reserved 3;
      reserved "legacy_status";
    
      CustomerStatus status = 4;
    }

    Removed field numbers and names should be reserved to prevent accidental reuse.

    Package Versioning

    package customer.v1;
    package customer.v2;

    A new versioned package can be introduced when an incompatible service or message contract is required.

    Protocol Buffer Compatibility Rules

    • Do not change the meaning of an existing field number.
    • Do not reuse a removed field number.
    • Reserve removed field names and numbers.
    • Add fields with new field numbers.
    • Avoid incompatible field-type changes.
    • Keep enumeration zero values safe and meaningful as unspecified values.
    • Do not assume all clients update simultaneously.
    • Run schema-compatibility checks before deployment.

    Consumer-driven Compatibility

    Schema comparison alone might not identify every client dependency. A consumer can rely on behaviour that remains structurally valid.

    Schema says:
    
    status is a string.
    
    
    Consumer assumes:
    
    status is always active or inactive.
    
    
    Server adds:
    
    pending_review
    
    
    Schema remains valid.
    
    Consumer can still fail.

    Compatibility testing should include representative consumer expectations, especially for critical internal or partner integrations.

    Contract Testing

    Automated compatibility checks can verify:

    • Removed endpoints
    • Removed fields
    • Changed field types
    • New required inputs
    • Changed enum values
    • Changed status-code contracts
    • Changed pagination defaults
    • Changed error schemas
    • Protocol Buffer field-number reuse
    • GraphQL breaking schema changes
    Contract Check Pipeline
    generate new contract → compare with released contract → detect breaking changes → run consumer tests → approve or reject release

    OpenAPI Version Metadata

    openapi: 3.1.0
    
    info:
      title: Customer API
      version: 2.0.0
    
    servers:
      - url: https://api.example.com/v2
    
    paths:
      /customers/{customerId}:
        get:
          operationId: getCustomer
          parameters:
            - name: customerId
              in: path
              required: true
              schema:
                type: string
          responses:
            "200":
              description: Customer found
              content:
                application/json:
                  schema:
                    $ref: "#/components/schemas/Customer"
    
    components:
      schemas:
        Customer:
          type: object
          required:
            - id
            - displayName
            - status
          properties:
            id:
              type: string
            displayName:
              type: string
            status:
              type: string
              enum:
                - active
                - inactive

    Maintain a separate published contract for every supported major version and verify that deployed runtime behaviour matches it.

    Deprecation Lifecycle

    Deprecation is a managed process, not merely a label in documentation.

    Identify replacement
            |
            v
    Mark old contract as deprecated
            |
            v
    Publish migration guide
            |
            v
    Notify known consumers
            |
            v
    Monitor remaining usage
            |
            v
    Test replacement adoption
            |
            v
    Apply announced retirement policy
            |
            v
    Remove old contract

    A deprecation notice should define:

    • The affected version or element
    • The reason for the change
    • The supported replacement
    • The migration procedure
    • The support policy
    • The retirement date when established
    • A contact or support channel

    Deprecation Response Fields

    An API can communicate lifecycle information through response fields in addition to documentation and direct consumer communication.

    HTTP/1.1 200 OK
    Deprecation: true
    Sunset: Wed, 30 Sep 2026 23:59:59 GMT
    Link: <https://developer.example.com/migrations/v1-to-v2>; rel="deprecation"
    Content-Type: application/json

    Use dates and links that match the published lifecycle policy. Do not add a retirement date until the organization has approved and can support it.

    Migration Guide

    A migration guide should focus on concrete client changes.

    Field Migration

    Version 1 Version 2 Client Change
    name displayName Read and write the new field
    total number total.amount string plus currency Parse explicit money representation
    Offset pagination Cursor pagination Store and return opaque cursors
    Unstructured error Problem-detail error Read the new error envelope

    A useful migration guide includes:

    • Before-and-after requests
    • Before-and-after responses
    • Field mapping
    • Error mapping
    • Pagination changes
    • Authentication changes
    • Code examples
    • Validation checklist
    • Rollback guidance

    Running Versions Concurrently

    Clients using v1
            |
            v
    API Gateway
            |
            +--> v1 Contract Adapter --+
            |                          |
    Clients using v2                   +--> Shared Application Services
            |                          |
            v                          |
    API Gateway                        |
            |                          |
            +--> v2 Contract Adapter --+

    Concurrent operation gives clients control over migration timing, but every active version adds implementation, testing, security, documentation, monitoring, and support cost.

    Security and Versioning

    An older version can remain contractually supported while requiring a security correction.

    Security considerations include:

    • Applying security patches to every supported version
    • Removing unsafe functionality through an approved emergency process
    • Preventing version selection from bypassing authorization
    • Maintaining consistent credential validation
    • Monitoring traffic to unsupported versions
    • Preventing deprecated versions from receiving new sensitive features unintentionally

    Security rule: Backward compatibility does not require preserving a security vulnerability. Security fixes need a documented risk, communication, and migration process.

    Versioning Metrics

    Useful lifecycle metrics include:

    • Request volume by version
    • Active consumers by version
    • Error rate by version
    • Latency by version
    • Deprecated endpoint usage
    • Deprecated field usage
    • Unsupported-version requests
    • Migration completion by known consumer
    • Compatibility-test failures
    • Security findings by supported version

    Version usage must be measured using an authorized caller or application identity where permitted, rather than relying only on raw request volume.

    Test Versioned APIs with curl

    Path Version

    curl -i \
      -H 'Accept: application/json' \
      https://api.example.com/v1/customers/cus_42
    curl -i \
      -H 'Accept: application/json' \
      https://api.example.com/v2/customers/cus_42

    Header Version

    curl -i \
      -H 'API-Version: 2' \
      -H 'Accept: application/json' \
      https://api.example.com/customers/cus_42

    Media-type Version

    curl -i \
      -H 'Accept: application/vnd.example.customer.v2+json' \
      https://api.example.com/customers/cus_42

    Replace example endpoints and credentials with approved test values. Test missing, supported, deprecated, and unsupported version selections.

    Versioning Review Workflow

    1. Document the proposed contract change.
    2. Compare the new contract with the released contract.
    3. Classify structural and behavioural compatibility.
    4. Identify affected consumers.
    5. Prefer an additive compatible design where possible.
    6. Introduce a new major contract when incompatibility is necessary.
    7. Publish updated machine-readable specifications.
    8. Run provider and consumer contract tests.
    9. Publish a migration guide and changelog.
    10. Deploy supported versions according to the lifecycle policy.
    11. Monitor adoption, errors, and deprecated usage.
    12. Retire the old version only through the communicated process.

    Common Versioning Mistakes

    1

    Creating a New Version for Every Change

    Compatible additive changes can normally evolve within the current contract without creating another major version.

    2

    Making Breaking Changes without a New Contract

    Removing or redefining fields can silently break existing clients.

    3

    Assuming Schema Compatibility Guarantees Behaviour

    Changes to ordering, defaults, validation, timing, or field meaning can break clients without changing the schema.

    4

    Defaulting to the Latest Version

    Deploying a new version should not silently move clients to a different contract.

    5

    Maintaining Versions through Copied Business Logic

    Duplicate implementations drift over time. Use version-specific contract adapters around shared application and domain logic where appropriate.

    6

    Deprecating without a Replacement

    Clients need a supported alternative and a clear migration path.

    7

    Removing a Version without Usage Evidence

    Monitor known consumers and deprecated traffic before retirement.

    8

    Changing Enum Behaviour Carelessly

    Existing clients can fail when they assume the documented set of values is permanently closed.

    9

    Reusing Protocol Buffer Field Numbers

    Old and new clients can interpret identical wire data as different fields.

    10

    Changing Pagination Ordering Silently

    Default ordering and cursor semantics are part of the collection contract.

    11

    Maintaining Unsupported Versions Indefinitely

    Every active version adds operational and security cost. Define a clear lifecycle policy.

    12

    Updating Documentation after Deployment

    The contract, migration guide, tests, and documentation should be ready before clients encounter the changed behaviour.

    Recommended Test Cases

    Test Expected Evidence
    Supported version The requested contract version handles the request
    Missing version The documented default or explicit error is returned
    Unsupported version The request fails through a stable error contract
    Additive response field Existing clients continue processing the response
    Old client against new deployment The supported client contract remains functional
    New client against old version The client handles unavailable capabilities according to contract
    Deprecated endpoint The response and documentation communicate deprecation consistently
    REST contract comparison Breaking schema changes are detected before release
    GraphQL schema comparison Removed or incompatible fields are detected
    Protocol Buffer comparison Field-number reuse and incompatible changes are rejected
    Authorization by version An older version cannot bypass current security policy
    Concurrent versions Each version returns its documented representation

    API Versioning Best Practices

    Recommended Practices

    • Define a written API compatibility policy.
    • Prefer additive backward-compatible changes.
    • Create a new major version only for necessary incompatible changes.
    • Review behavioural compatibility as well as schema compatibility.
    • Use one consistent version-selection strategy.
    • Define missing and unsupported version behaviour.
    • Do not silently move clients to the latest version.
    • Maintain a machine-readable contract for every supported major version.
    • Separate version-specific adapters from shared business logic.
    • Automate REST, GraphQL, and Protocol Buffer compatibility checks.
    • Run consumer contract tests for critical integrations.
    • Publish changelogs and migration guides before deployment.
    • Deprecate before removing supported contract elements.
    • Provide a supported replacement for deprecated functionality.
    • Monitor version and deprecated-feature usage.
    • Apply security fixes to every supported version.
    • Prevent old versions from bypassing current authorization controls.
    • Limit the number of concurrently supported major versions.
    • Test rollback and parallel-version routing.
    • Retire versions only through the documented lifecycle process.

    Practice Exercise

    Evolve the earlier versioned customer and order API from version 1 to version 2 while preserving version 1 for existing clients.

    Requirements

    1. Publish separate OpenAPI contracts for version 1 and version 2.
    2. Keep the version 1 contract operational.
    3. Rename name to displayName in version 2.
    4. Replace a numeric total with an explicit money representation.
    5. Move version 2 order listing from offset to cursor pagination.
    6. Introduce a consistent problem-detail error format in version 2.
    7. Use version-specific request and response adapters.
    8. Reuse shared application and domain services.
    9. Define missing and unsupported version responses.
    10. Add automated contract-difference checks.
    11. Add consumer tests for version 1 clients.
    12. Publish a version 1 to version 2 migration guide.
    13. Add deprecation metadata after lifecycle approval.
    14. Monitor request volume by version.
    15. Document the controlled version 1 retirement criteria.

    Migration Matrix

    Contract Area Version 1 Version 2 Migration Action
    Customer name name displayName Update request and response mapping
    Order total Numeric amount Amount string and currency Adopt explicit money object
    Pagination Offset and limit Opaque cursor and limit Store and return continuation cursor
    Error format Plain message Structured problem detail Update client error parser
    Version selection /v1 /v2 Update endpoint base path

    Frequently Asked Questions

    1

    What is API versioning?

    API versioning manages different contract generations so clients can use and migrate between supported behaviours predictably.

    2

    Does every API change require a new version?

    No. Additive backward-compatible changes can normally be introduced within an existing major version.

    3

    What is a breaking change?

    A breaking change requires an existing supported client to change its implementation to continue working correctly.

    4

    Can a change be breaking without changing the schema?

    Yes. Changes to field meaning, ordering, validation, errors, consistency, or retry behaviour can break clients while preserving the schema.

    5

    Which API versioning strategy is best?

    There is no universal choice. Select a strategy based on client usability, routing, caching, documentation, negotiation, and lifecycle requirements, then apply it consistently.

    6

    Should a missing version use the latest API?

    No. Missing-version behaviour should be stable and documented. It should not change silently whenever a new version is deployed.

    7

    How is GraphQL versioned?

    GraphQL commonly evolves one schema through additive fields and controlled deprecation. Incompatible removals still require a managed migration.

    8

    How is gRPC versioned?

    gRPC contracts evolve through compatible Protocol Buffer changes. A new versioned package can be introduced when an incompatible service contract is necessary.

    9

    Why must removed Protocol Buffer field numbers be reserved?

    Reserving them prevents old and new clients from interpreting the same wire field number as different data.

    10

    What is API deprecation?

    Deprecation communicates that a currently supported version or contract element is planned for replacement or future removal.

    11

    When can an old version be removed?

    Removal should follow the published lifecycle policy after migration guidance, consumer communication, usage monitoring, and approved retirement criteria.

    12

    What comes after versioning?

    The next topic is idempotency, followed by authentication versus authorization and rate-limit semantics.

    Key Takeaway

    API versioning manages incompatible contract evolution, while backward compatibility allows existing clients to continue working without a required migration. Prefer additive changes, review behavioural as well as structural compatibility, and introduce a new major version only when incompatibility is necessary. Use one consistent selection strategy, publish machine-readable contracts, automate compatibility checks, provide migration guidance, monitor adoption, apply security fixes to all supported versions, and retire older versions only through a documented deprecation and lifecycle process.