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.
Table of Contents
- 1. Why silent API retirement breaks integrations
- 2. The Deprecation header: immediate marking as outdated
- 3. The Sunset header: the concrete retirement date
- 4. Pointing to the successor version with the Link header
- 5. How much lead time a fair retirement needs
- 6. Monitoring actual usage of deprecated endpoints
- 7. Behavior after the actual retirement date
- 8. Documenting deprecation in the OpenAPI specification
- 9. Sunset and Deprecation headers at a glance
- 10. Summary
- 11. FAQ
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.
4. Pointing to the successor version with the Link header
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 |
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.