Website Spec
ResilienceOptionalUpdated

Deprecation and Sunset

When you retire an endpoint, announce it in machine-readable form: the Deprecation and Sunset response headers tell clients it is going away, when, and where to go next — so integrations migrate before anything breaks.

What it is

When you retire an HTTP endpoint — an old API version, a moved feed, a well-known URI you no longer serve — two response headers let you announce it in machine-readable form so clients migrate before anything breaks.

  • Deprecation (RFC 9745) marks a resource as deprecated. Its value is a date: Deprecation: @1717200000. A date in the past means it was deprecated then; a future date means it will be. The resource still works — this is advance notice.
  • Sunset (RFC 8594) gives the date the resource is expected to stop responding: Sunset: Tue, 30 Jun 2026 23:59:59 GMT. It should be a future date while the resource is live; once it passes, requests typically return 410 Gone.

The Sunset date must not be earlier than the Deprecation date. Pair either header with a Link: rel="deprecation" points to human documentation about the change, rel="sunset" to a retirement or migration policy, and rel="successor-version" to the replacement.

Why it matters

  • Clients and agents find out on their own. A consumer hitting the endpoint reads the date and the link, and schedules migration — no out-of-band emails or guesswork.
  • It turns a silent break into a planned one. Without these headers an endpoint simply vanishes one day and every integration fails at once.
  • The signal is auditable. Anyone can curl -I the endpoint and see when it is going away and where to go next.
  • It complements a real status code. A retired URL should still return the right status (404/410) and, where a replacement exists, a redirect; these headers add the when and why.

How to implement

While the resource is still live, emit the headers and keep serving it normally:

Deprecation: @1717200000
Sunset: Tue, 30 Jun 2026 23:59:59 GMT
Link: <https://api.example.com/v2/orders>; rel="successor-version",
      <https://developer.example.com/deprecation/orders-v1>; rel="deprecation"

Announce as early as you can — the point is lead time. Do not start failing before the Sunset date. Once the resource is genuinely gone, return 410 Gone (or 404); you may keep the Sunset header to record when it went, plus a rel="deprecation" link so latecomers still find the explanation. RFC 8594 explicitly covers this post-sunset 410 case.

This site ships a worked example. /.well-known/ai.txt was retired, and rather than a bare 404 it returns 410 Gone carrying Deprecation, Sunset, and a rel="deprecation" link back to this page (see functions/_middleware.ts). The ai.txt convention itself proved defunct — express AI-crawler preferences via robots.txt and content signals instead.

Announcing your own support window

The headers are usually read as “this URL is being retired”, but they answer a broader question: how long will this keep working? That question also arises when nothing is being retired at all — when a still-valid way of talking to your endpoint is one you intend to stop accepting.

Our MCP server is the case in point. The 2026-07-28 revision of the protocol replaced the initialize handshake with per-request negotiation, but it did not deprecate the handshake: the older revisions are Final, not withdrawn, and the protocol says nothing about when a server should stop honouring them. That makes the support window a decision by the server, not by the specification — and a decision nobody can discover by reading the standard. So responses to a legacy initialize carry Deprecation, a Sunset of 28 July 2027, and a rel="deprecation" link, while the endpoint itself carries nothing: /mcp is not going anywhere, only our willingness to answer the handshake on it. See MCP and tool discovery.

Two things make that legitimate rather than a misuse of the headers. The scope is a real one — the response to a particular request, not the URL in general — and the commitment is one we are actually making and can be held to. If you borrow this pattern, be clear in your own documentation that the dates are yours. Attributing them to an upstream standard that never set them is a claim someone will check.

Common mistakes

  • A Sunset earlier than Deprecation. Invalid per RFC 9745.
  • Emitting Deprecation but never a Sunset or a successor link — consumers learn it is deprecated but not when it dies or what to use instead.
  • Failing the resource before the announced Sunset. Deprecation is a promise to keep working until then.
  • Using a bare Deprecation: true. The value is a structured-field date, not a boolean.
  • Announcing a sunset you have no intention of honouring, because a standard “moved on” from a feature. Check whether the thing is actually scheduled for removal; if the date is your policy rather than the standard’s, say so.

Verification

curl -sI https://api.example.com/v1/orders | grep -iE 'deprecation|sunset|link'

Confirm Deprecation carries a date, Sunset is not earlier, and a rel="deprecation" or rel="successor-version" link is present. On a fully retired URL, confirm the status is 410/404, not 200.

Related topics

Sources & further reading