API versioning

One version per channel - deprecation, sunset dates, successor links and usage reports.

APIs evolve and, sooner or later, a change arrives that existing clients cannot absorb - a renamed field, a restructured response, a different resource layout. This page shows the complete lifecycle of an API version in Zato: publish a new major version, deprecate the old one, tell its callers where to go, watch who still uses it, and retire it once the traffic reaches zero.

The pattern - one version, one channel

Zato uses URL path versioning - the version is part of the endpoint's URL path and each major version is its own REST channel:

  • /api/v1/orders - a channel pointing to the service that implements version 1
  • /api/v2/orders - a channel pointing to the service that implements version 2

No routing code is needed - channels already map URL paths to services. Both versions run side by side and each has its own security definition, rate limiting and audit log.

The two channels may point to two different services or to a shared one, depending on the size of the change:

# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class GetOrdersV1(Service):
    """ The original contract, kept unchanged for existing callers.
    """
    def handle(self):
        orders = self.invoke('orders.get-list')
        self.response.payload = {'orders': orders}

class GetOrdersV2(Service):
    """ The new contract - here, pagination metadata alongside the results.
    """
    def handle(self):
        orders = self.invoke('orders.get-list')
        self.response.payload = {
            'items': orders,
            'total': len(orders),
        }

Minor, backwards-compatible changes - a new optional field, a new query parameter - do not need a new version. Only breaking changes do.

Deprecate the old version

Once the new version is live, mark the old channel as deprecated. In the Dashboard, go to Connections > Channels > REST, edit the channel and click Toggle options next to API versioning to reveal the deprecation fields:

  • Deprecated - the flag itself
  • Sunset date - next to the flag, the day the channel will be retired, picked with a date-time picker, e.g. 2026-12-31
  • Successor path - the URL path of the replacement, e.g. /api/v2/orders
Deprecation fields on a channel

The sunset date and the successor are optional - the flag alone already marks the channel. A deprecated channel keeps working exactly as before, nothing is blocked or slowed down - deprecation is a signal, not a switch.

The channel list shows a Deprecated badge next to the name of every deprecated channel, so the state is visible at a glance.

The same attributes are available in enmasse definitions, so deprecation can be managed through configuration files too:

channel_rest:

  - name: api.orders.v1
    service: api.get-orders-v1
    url_path: /api/v1/orders
    is_deprecated: true
    deprecation_sunset: '2026-12-31'
    deprecation_successor: /api/v2/orders

What callers see

Every response from a deprecated channel includes the standard deprecation headers, including error and rate-limited responses:

Deprecation: @1767225600
Sunset: Thu, 31 Dec 2026 00:00:00 GMT
Link: </api/v2/orders>; rel="successor-version"
  • Deprecation - when the channel became deprecated, per RFC 9745
  • Sunset - when it will be retired, per RFC 8594
  • Link - where the replacement lives, with the successor-version relation

Clients and API tooling that understand these headers can raise the migration with their owners before the retirement date arrives - without any coordination on your side.

The OpenAPI console shows the same information - a deprecated endpoint has a deprecated badge and its description names the sunset date and the successor path, so anyone browsing the live documentation learns about the migration too.

Who still calls the old version

The decision to retire a version needs evidence - who still calls it and how often. Each REST channel has a usage report built over its audit log - in the channel list, click Usage next to the channel.

The report shows one row per caller, where the caller is the security definition that authenticated the requests:

  • Caller - which API client the calls came from
  • Calls - how many calls the caller made in the selected range
  • First and last call - when the caller's traffic started and when it was last seen

The range covers the last 24 hours, the last 7 days or the audit log's full retention window, each row links to the filtered audit log page with the underlying requests, and the table exports to CSV. When a caller's traffic reaches zero, that client has migrated - when all of them have, the version can be retired by deleting the channel.

For longer-horizon trends, the Prometheus metrics expose per-channel request counters that a monitoring stack can graph over any period.

The lifecycle at a glance

  1. Publish /api/v2/orders as a new channel pointing to the new service
  2. Mark /api/v1/orders as deprecated, with a sunset date and /api/v2/orders as the successor
  3. Callers see the Deprecation, Sunset and Link headers on every response and the deprecated entry in the OpenAPI console
  4. Watch the usage report as clients migrate
  5. Retire the old version by deleting its channel once the traffic reaches zero

See also

PageWhat it covers
REST channelsThe channels each API version runs on
OpenAPI consoleWhere callers see deprecation badges and sunset dates
Enmasse referenceis_deprecated and the other channel keys in YAML

Learn more