How AI is applied across API Evangelist and APIs.io. Read my AI disclosure →
API Evangelist API Evangelist
Discovery
Learnings
Guidance
Toolbox
Alignment
API Evangelist LLC

OpenAPI Overlays for Deprecation and Migration Choreography

August 14th, 2026 · Kin Lane
OpenAPI Overlays for Deprecation and Migration Choreography

Deprecation is where most API programs quietly fall apart. Not because teams don’t know how to sunset an operation, but because they do it by hand, one operation at a time, across a dozen specs, on whatever day someone finally gets to it. Somebody sets deprecated: true in one place, forgets the Sunset header in another, writes “please migrate soon” in a description here and “this endpoint is going away” there, and six weeks later nobody can tell you which version of the truth is actually live. This is the use case from my many use cases for OpenAPI Overlays post that I think is the most underused, and honestly the most emotionally satisfying to solve: deprecation and migration choreography. An overlay lets you mark a whole wave of endpoints deprecated with identical language, schedule it for the sunset date, and — this is the part that changes how the whole thing feels — roll it back if you have to.

I’m working against the Products API teaching template I keep coming back to, whose canonical OpenAPI lives at https://raw.githubusercontent.com/api-evangelist/products-api/main/openapi/products-api-openapi.yml. Say we’re retiring the cancel operation in favor of a proper refund flow. Here is the first overlay, which marks that operation deprecated, prepends a consistent sunset line to its description, and documents a Sunset response header so consumers get told the same thing in the spec that the running gateway will tell them at runtime.

overlay: 1.1.0
info:
  title: Deprecate cancel in favor of refund
  version: 1.0.0
extends: https://raw.githubusercontent.com/api-evangelist/products-api/main/openapi/products-api-openapi.yml
actions:
  - target: $.paths['/products/{id}/cancel'].post
    update:
      deprecated: true
      description: |
        Deprecated: sunset 2027-01-01, use POST /products/{id}/refund instead.
      responses:
        '200':
          headers:
            Sunset:
              description: RFC 8594 sunset date after which this operation is removed.
              schema:
                type: string
                example: 'Sat, 01 Jan 2027 00:00:00 GMT'
            Deprecation:
              description: RFC 9745 deprecation flag; true once this operation is deprecated.
              schema:
                type: string
                example: 'true'

A few things worth being precise about, because deprecation is exactly where people play fast and loose with the HTTP conventions. The Sunset header comes from RFC 8594 and carries an HTTP-date — a full IMF-fixdate like Sat, 01 Jan 2027 00:00:00 GMT, not a bare 2027-01-01. The Deprecation header is standardized in RFC 9745 and, in its current form, is a boolean-ish true rather than a date, with the actual timeline expressed via Sunset and a Link relation pointing at the replacement. I’m documenting both in the spec so the contract matches the runtime, and I’m setting deprecated: true so every tool that reads the OpenAPI — docs, SDK generators, linters — shows the strikethrough without anyone editing the source.

The single-operation overlay is the demo. The real win is a template you apply across many operations and many specs with the same words every time. Overlays match with JSONPath, so I can select every operation carrying a given tag and stamp them all at once. Here is the reusable pass.

overlay: 1.1.0
info:
  title: Scheduled deprecation wave - retiring legacy tag
  version: 1.0.0
extends: https://raw.githubusercontent.com/api-evangelist/products-api/main/openapi/products-api-openapi.yml
actions:
  - target: $.paths.*[?(@.tags && 'legacy' in @.tags)]
    update:
      deprecated: true
      description: |
        Deprecated: sunset 2027-01-01. This operation is scheduled for removal;
        consult the migration guide for the supported replacement.

That one target sweeps every operation tagged legacy — across this spec and, with the extends pointed elsewhere, across any other spec that shares the convention. Same sunset date, same sentence, no drift. Because it’s an overlay per the Overlay spec, the source specs never change. You preview the merged result in a pull request and read the diff. You apply it in CI on the morning of the sunset date. And if the migration slips, or a big customer screams, you delete the overlay from the pipeline and the next build ships clean, undeprecated specs — no frantic git archaeology to figure out which hand-edits to reverse.

That reversibility is the whole argument. A deprecation done as scattered manual edits is a one-way door you walk through nervously. A deprecation done as an overlay is a diffable, reversible artifact you can preview, schedule, and undo. Sunsetting an API is stressful enough without also making it irreversible — stop hand-editing your specs into a corner and let the deprecation be a file you can throw away.