Using Sunset and Deprecation Headers for API Retirement in Practice
AI generated
{ }
GET
API Lifecycle · HTTP Headers
Using Sunset and Deprecation Headers in Practice
How an API retirement gets communicated instead of blindsiding integrators

An API endpoint that disappears without warning breaks every integration using it and damages external developer teams' trust in the entire API. The Deprecation and Sunset HTTP headers from RFC 8594 offer a standardized way to communicate an upcoming retirement early and in a machine-readable form, so clients can react in time.

14 min read Sunset Header · RFC 8594 API Lifecycle

1. Why silent API retirement breaks integrations

External development teams integrating a REST API usually have no direct insight into the API operator's internal roadmap and typically only learn of a retirement once their own application starts failing. This kind of communication through production outages instead of proactive announcement damages trust in the API in a lasting way and often forces urgent, unplanned emergency migrations on the integrator's side.

A controlled retirement therefore needs a communication channel built directly into the API responses themselves, instead of relying on changelogs, mailing lists, or blog posts that integrators may never read. This is exactly the role the Deprecation and Sunset headers play.

Unlike a one-off blog post, an HTTP header reaches every client on every actual request, which significantly reduces the chance that an announcement simply gets missed because it was published at the wrong time or buried in a rarely read newsletter.

2. The Deprecation header: immediate marking as outdated

The Deprecation header signals that an endpoint is marked as deprecated, either with the value true or with a concrete date from which the marking applies. Clients evaluating this header can log early warnings or notify development teams long before the endpoint is actually retired.

It's important that the Deprecation header alone does not yet make any statement about the exact retirement date, only communicating the status. The separate Sunset header is responsible for the concrete timing of the final retirement, making both headers together a complete communication pair.

In practice, it's worth setting the Deprecation header as soon as the internal decision to retire an endpoint is final, even before the exact Sunset date has been settled, so attentive integrators can already start planning their migration ahead of time.


<?php
declare(strict_types=1);

use Symfony\Component\HttpFoundation\Response;

final class DeprecatedEndpointHeaderSubscriber
{
    private const DEPRECATED_ROUTES = [
        'api_orders_v1_list' => new \DateTimeImmutable('2026-12-31T23:59:59+00:00'),
    ];

    public function onKernelResponse(Response $response, string $routeName): void
    {
        if (!isset(self::DEPRECATED_ROUTES[$routeName])) {
            return;
        }

        $sunset = self::DEPRECATED_ROUTES[$routeName];
        $response->headers->set('Deprecation', 'true');
        $response->headers->set('Sunset', $sunset->format(\DateTimeInterface::RFC7231));
        $response->headers->set(
            'Link',
            '</api/v2/orders>; rel="successor-version"'
        );
    }
}

3. The Sunset header: the concrete retirement date

The Sunset header contains a concrete date in HTTP date format from which the endpoint will no longer be available. Unlike the Deprecation header, the Sunset header is explicitly forward-looking and machine-readable, so automated monitoring systems on the integrator's side can trigger warnings once the sunset date falls within a configured lead time (for example 30 days ahead).

RFC 8594 explicitly specifies that the Sunset header is not a guarantee that the endpoint will be retired at exactly that point, but a statement of intent. An API operator should still reliably honor the date once it has been communicated through this header, so as not to unsettle integrators through repeated postponements.

Another practical aspect is that a once-communicated sunset date should not be moved earlier without damaging trust: once integrators have aligned their migration planning with the announced date, that date should be treated as binding, even if internal priorities shift.

Deprecation and Sunset alone tell a client it needs to act, but not where to move to. The Link header with the successor-version relation, also part of the RFC 8594 ecosystem, points directly to the URL of the replacement endpoint, so integrators can start the migration without a separate documentation search.

In practice, it's also worth adding a Link header with the deprecation relation, pointing to a human-readable explanation page with a migration guide, since machine-readable headers alone are rarely enough to plan a complete migration. Both link relations can be set in parallel in the same response.

5. How much lead time a fair retirement needs

The appropriate lead time between the first deprecation marking and the actual retirement depends heavily on the user base: an internal API with a few known consumers can get by with a few weeks of lead time, while a public API with thousands of unknown integrators often needs six months or longer to realistically give all teams time to migrate.

A proven practice is a staged process: first only the Deprecation header without a fixed date, then after an observation phase with declining usage adding a concrete Sunset date with sufficient lead time, and only after reaching that date the actual retirement, ideally with a transition phase in which the old endpoint still responds with HTTP 410 Gone instead of disappearing entirely.

6. Monitoring actual usage of deprecated endpoints

A sunset date without knowledge of the actual remaining usage is risky: an endpoint with continued high traffic shortly before the planned retirement date suggests many integrators have missed the warning, and retiring it on schedule would cause significant outages. Access logs tracking usage per endpoint and ideally per API key make visible which specific integrators still need to migrate.

For critical APIs, it's worth identifying affected integrators directly through API key usage and contacting them proactively, instead of relying exclusively on HTTP header communication. This proactive follow-up reduces the risk that the retirement, despite technically correct communication, still causes real production outages for integrators.

7. Behavior after the actual retirement date

After the sunset date, the endpoint should not simply respond with HTTP 404 Not Found, which gives integrators no clue about the reason, but with HTTP 410 Gone, which explicitly signals that the resource was intentionally and permanently removed. The response should still include the Link header to the successor version, so even late integrators can still find the correct migration path.

A transition phase of a few weeks with HTTP 410 Gone instead of complete route removal gives late integrators a clear, machine-readable error instead of a confusing generic 404, before the endpoint is finally removed entirely from the routing.

8. Documenting deprecation in the OpenAPI specification

In addition to the runtime headers, the OpenAPI specification itself should set the deprecated flag at the operation level, so generated client SDKs and interactive documentation like Swagger UI already show the deprecated status before the first actual request. Many code generators automatically mark methods generated from deprecated operations with language-native deprecation annotations (such as @deprecated in PHPDoc), which warns development teams already at compile time or in the IDE.

This dual communication, both at development time through the OpenAPI specification and at runtime through HTTP headers, covers different points in the integration process and reduces the likelihood that a team completely misses the retirement notice.

9. Sunset and Deprecation headers at a glance

The table below summarizes which headers carry which information and when they are used.

Header Purpose Example value
Deprecation Signals deprecated status true
Sunset Concrete retirement date Wed, 31 Dec 2026 23:59:59 GMT
Link (successor-version) Points to successor endpoint ; rel="successor-version"
Link (deprecation) Points to migration guide ; rel="deprecation"

Mironsoft

OpenAPI design, Symfony APIs, and API security

APIs that external teams can integrate without back-and-forth questions?

We review existing REST APIs for inconsistent error formats, missing OpenAPI documentation, and security gaps, then build an API that is clearly documented, versioned, and hardened against abuse.

API Review

Checking the OpenAPI spec, error formats, and status codes for consistency.

Symfony Implementation

Using DTOs, Serializer, and Validator for clean, type-safe request/response models.

Security Audit

Hardening rate limiting, auth schemes, and input validation against real attack surfaces.

10. Summary

Sunset & Deprecation: The Essentials at a Glance

Deprecation

Marks an endpoint as deprecated, without necessarily naming a concrete retirement date.

Sunset

States the concrete, planned retirement date in HTTP date format per RFC 8594.

Link header

Machine-readably points to the successor endpoint and a human-readable migration guide.

410 instead of 404

After retirement, HTTP 410 Gone signals a deliberate, permanent removal.

11. FAQ: Sunset & Deprecation: The Essentials at a Glance

1Are Deprecation and Sunset headers official standards?
Yes, both are specified in RFC 8594 and are used by many major APIs (such as GitHub, Stripe).
2Do I always have to set both headers together?
Not necessarily. Deprecation can be set early without a concrete date, Sunset only gets added once a date is fixed.
3How long should the lead time be for a public API?
Often six months or longer, depending on the size and responsiveness of the integrator base. Internal APIs usually need less.
4What happens if a client ignores the Sunset header?
After the sunset date the endpoint responds with HTTP 410 Gone, so the client gets a clear error instead of a silent failure.
5Can I postpone sunset dates after announcing them?
Technically yes, but it undermines trust in future announcements. Postponements should stay the exception, not the rule.
6Is OpenAPI documentation alone enough for deprecation?
No, many integrators don't regularly re-read the specification. Runtime headers reach clients on every actual request.
7How do I find out which integrators still need to migrate?
Through access logs per API key, showing which specific clients are still actively using the deprecated endpoint.
8Why 410 Gone instead of 404 Not Found after retirement?
410 explicitly signals a deliberate, permanent removal, while 404 could also just mean a random typo in the URL.
9Do common HTTP client libraries handle these headers automatically?
The headers are transmitted, but automatic evaluation (logging, warnings) usually needs to be implemented in the client itself.
10Does this approach also apply to GraphQL APIs?
GraphQL has its own @deprecated directive at the field level, which works conceptually similarly but is not based on HTTP headers.