API changes

The API sunset header, and when to send one

5 min read

Sunset is a single response header, defined in RFC 8594, that tells a caller when a resource will stop answering. API deprecation covers the full announce-remind-brownout-retire timeline and the notices that go with it; this is about the one machine-readable signal in that timeline, what it actually says, and the one case where the RFC itself says not to send it.

What does the Sunset header say, and what doesn’t it say?

It carries a single HTTP-date, the point at which the resource is expected to become unresponsive:

Sunset: Sat, 31 Dec 2028 23:59:59 GMT

The RFC calls it a hint, not a guarantee: it does not promise the resource will keep working right up to that timestamp, and it says nothing about what failure will look like afterward. Callers may get a 4xx, a redirect, or no response at all; the header does not distinguish. A timestamp already in the past means “now, or any time” rather than an error in the value. None of this is enforced by the protocol. A client that never reads the header behaves exactly as it always did, and finds out the resource is gone the same way it would have found out anyway.

When should you actually send it?

Only once the resource is genuinely going to stop responding, not while it is merely no longer the recommended choice. The RFC is explicit that deprecation happens in two stages, and the Sunset header field belongs to the second one only: the API remains fully operational during the first stage, the announcement that a version is no longer preferred, and the header field does not apply there. It applies once the version is actually scheduled to become unresponsive.

That maps directly onto the deprecation timeline: the Deprecation header goes out from day one, at the announcement step; Sunset describes the date the old behaviour will actually stop, which is the same date the four-step timeline calls the retirement. Sending Sunset on day one is not wrong, since the date is already fixed by then, but sending it without also having announced a deprecation, or setting it for a version you have not actually committed to retiring, tells callers something you have not decided yet.

Does it interact with caching?

No, and the RFC says so directly: Sunset and HTTP caching solve unrelated problems and should be read as complementary, not overlapping. Caching headers say when a cached copy is safe to reuse; Sunset says nothing about the resource’s current state, only that the resource itself will stop existing. A response can be fully cacheable right up to the moment it sunsets. Do not use one to approximate the other, and do not assume a long max-age cancels out an approaching sunset date, or the reverse.

Can one header sunset more than one endpoint?

The header applies to the resource that returned it, but the RFC allows a service to document a wider scope: a Sunset date on an API’s home resource can be defined to mean the whole API is going, not just that one URL. The catch is that this only works for callers who already know your scoping rule. A caller reading the header at face value sees a sunset on the one resource it requested and nothing else, so a wider scope has to be written down somewhere a caller can find it, not implied.

What should ship alongside the header?

A link to where the retirement is explained. RFC 8594 registers its own sunset link relation for exactly this: pointing at a resource that describes the retirement policy, the upcoming date, or how to migrate, separately from the header’s bare timestamp.

HTTP/1.1 200 OK
Sunset: Sat, 31 Dec 2028 23:59:59 GMT
Link: <https://example.com/docs/sunset-policy>; rel="sunset"

Pointing that link at your own changelog examples or a dedicated migration page turns a header almost nobody’s client code inspects into something a human who does go looking finds immediately. Combine it with the successor-version relation from the deprecation headers and a caller gets both where to go and what replaces this one, from the response alone.

What does this look like end to end?

Say v1 is going away on 1 March 2027. The deprecation announcement on day one adds Deprecation and Link: rel="successor-version" to every v1 response, per the deprecation headers, but holds off on Sunset until the retirement date is truly fixed rather than a placeholder. Once it is, every v1 response carries:

HTTP/1.1 200 OK
Deprecation: @1756425600
Sunset: Mon, 01 Mar 2027 00:00:00 GMT
Link: <https://api.example.com/v2/reports>; rel="successor-version"
Link: <https://example.com/docs/sunset-policy>; rel="sunset"

A caller’s gateway or monitoring can alert on either header independently: Deprecation says a newer version exists, Sunset says this one has a clock on it. Neither header is required to change before 1 March; what changes is the response itself, on the day, and during any brownout windows scheduled before it.

Does a brownout change what the header says?

The header value itself does not need to move for a scheduled brownout: the sunset date is still the sunset date, whether or not the resource is intermittently failing before it. What changes is the response, not the header. Scheduling short windows of 410 Gone in the weeks before the announced date, as API deprecation describes, is what turns a caller’s first contact with the failure into a rehearsal rather than the real thing on the day the header’s date arrives.

FAQ

Do any real HTTP clients or tools actually read the Sunset header? Rarely, on the client side. Its value is mostly for whoever operates infrastructure between you and the caller: an API gateway or a monitoring tool you configure to watch for the header can alert your own team, or a partner’s, well before the caller’s code would ever notice. Treat it as a signal you build tooling around, not one you can assume the other side already has.

Is Sunset the same thing as Cache-Control: max-age? No. max-age is about how long a cached copy stays valid; Sunset is about when the resource stops existing at all. A response can carry a short max-age and a Sunset date years away, or the reverse, and neither header constrains the other.

Can I send Sunset for a single field going away, not the whole endpoint? No, the header is scoped to the resource, meaning the URL, not to a field inside its response body. For a field, a parameter or an enum value that is going away while the endpoint itself stays up, use the Deprecation header and a changelog entry instead; API deprecation covers announcing exactly that kind of change.

What if the sunset date needs to move? Update the header value and say so in the changelog entry that announced it in the first place; silently changing a published date is how a caller decides none of your dates are real. The RFC frames the value as a hint precisely because dates do sometimes move, but a moved date without an explanation costs you the next one too.


The technical claims in this article have not been independently reviewed. If something here is wrong, tell us and we will correct it.

Related on changeloop: Developer docs, Changelog examples

changeloop
The team building a closed-loop changelog. Your users ask, your team ships, the person who asked gets told.