On this page
Deprecate, sunset, remove: three different moments
| Moment | What it means | Does the endpoint still work? |
|---|---|---|
| Deprecated | Callers should stop using it and move to the replacement | Yes. RFC 9745 says deprecation does not change its behaviour |
| Sunset | The date after which it is expected to stop answering | Until that date, as a hint, not a promise (RFC 8594) |
| Removed | The route is gone from the code and the spec | No: callers get 404 or 410 Gone |
Keep the three apart in your notice. “Deprecated” without a sunset date reads as “someday”, and teams rightly put it at the bottom of the backlog.
The checklist
Name the owner of the retirement
One team decides the dates, answers questions and does the removal. Usually it is the team that owns the endpoint. If nobody owns it, settle that first: an endpoint with no owner has nobody to approve the removal or to call when something breaks.
Find every consumer team
Start from what is written down (a dependency map, catalog entries, earlier notices), then search the code and the access logs for callers the list misses. How to find which teams use an endpoint walks through each search. The output is a list of teams, each with a person who can answer.
Have the replacement ready first
Ship the new endpoint, document the mapping from old to new, and make sure it covers what callers use today. A deprecation notice that says “a replacement is coming” starts a second round of notices later.
Tell the consumer teams, with dates
Send the notice to those teams in the channels they read, not to a company-wide list. Give a deprecation date, a sunset date, the replacement and a reply deadline. Track the replies per team: migrated, in progress, or not ours. A template is below.
Mark it in the spec and in the responses
Set
deprecated: trueon the operation in the OpenAPI spec and name the replacement in its description. Add theDeprecationandSunsetresponse headers, with aLinkto the migration notes. They help clients that log them; they do not replace the notice.Watch the traffic until it reaches zero
Count calls to the endpoint per caller, every week. Chase the callers that are not on your list: they are the teams the notice did not reach. Wait a full business cycle at zero, including a month end, so a monthly job has had its chance to call.
Remove it, and answer with 410 for a while
Remove the route from the code and the operation from the spec in the same change. If you can, answer the old path with 410 Gone for a few weeks, so a missed caller gets a clear error instead of a confusing 404.
Deprecation and Sunset headers
Two HTTP response headers tell a client, in the response itself, that an endpoint is on its way out. Both are optional for the client: a client that does not read them works exactly as before, so they reach only the callers whose code or logs look for them.
HTTP/1.1 200 OK
Deprecation: @1798761599
Sunset: Wed, 31 Mar 2027 23:59:59 GMT
Link: <https://docs.example.com/orders/invoice-v2>; rel="deprecation"; type="text/html"- `Deprecation` (RFC 9745, Standards Track, March 2025): a structured-field date, written as
@and Unix seconds.@1798761599is 31 December 2026, 23:59:59 UTC. The date may be in the past. The endpoint keeps working. - `Sunset` (RFC 8594, Informational, May 2019): an HTTP-date after which the endpoint is expected to stop answering. The RFC calls it a hint: the date can move, and the endpoint may go earlier or later.
- Order: RFC 9745 says the
Sunsetdate must not be earlier than theDeprecationdate. The two use different date formats for historical reasons. - `Link` with `rel="deprecation"` points to a page for people: what replaces the endpoint and how to move. RFC 8594 defines
rel="sunset"for a page about the retirement policy.
paths:
/orders/{id}/invoice:
get:
deprecated: true
description: >-
Deprecated. Use GET /invoices/{id} instead.
Removal planned for 31 March 2027.In OpenAPI, deprecated: true on an operation says consumers should stop using it. It changes nothing at runtime: the endpoint answers as before, and the flag reaches only people and tools that read the spec.
A notice you can copy
Subject: GET /orders/{id}/invoice will be removed on 31 March 2027
Your team is listed as a consumer of GET /orders/{id}/invoice (orders-api).
What changes: the endpoint will return 410 Gone after 31 March 2027.
What to use: GET /invoices/{id}. Migration notes: <link>
Why: invoices moved to billing-api.
What we need: reply "migrated", "in progress (date)" or "not ours" by 15 January 2027.
Questions: #orders-api, or the owner, <team>.One notice per team, with a reply deadline, beats one announcement for everyone. A team that replies “not ours” is useful too: it takes a name off the list, or tells you the list was wrong.
Where Graphwake fits: who is affected
Graphwake answers step 2 and shows the reach of the final step. It keeps which teams subscribe to each endpoint, read from your OpenAPI specs and the teams’ own subscriptions, and alerts those teams on a breaking change to the endpoint, and always when it is removed.
The consumer list is already there
Each endpoint shows its owner and the teams that subscribe to it. Start the retirement notice from that list instead of a search; an endpoint no team subscribes to is flagged as an orphan.
Removal is always breaking
Removing an endpoint from the spec is always a breaking change in Graphwake. It alerts the subscribed teams in Slack, Microsoft Teams or email. Through the CI step, that happens while the removal is still a pull request.
The removal gets an impact score
A removed endpoint counts as a breaking change and as a blind spot, and each subscribed team adds to the impact score. The reviewer sees how far the removal reaches before the merge.
A move in one spec update is flagged
When the old endpoint is removed and its replacement added in the same spec update, the alert says the endpoint may have been moved and lists the endpoints added with it, and Discovery suggests the replacement to the teams that subscribed to the old one. Someone confirms before it becomes a subscription.
To keep the consumer list itself current, see the team-level API dependency map. For what happens when the removal reaches the subscribed teams, see API breaking change alerts.
When traffic data alone is enough
- You need proof that nobody calls the endpoint. Gateway analytics, access logs or traces over a long enough window show that.
- Your callers are external customers with API keys. Gateway analytics already list each caller and its volume.
Questions
What is the difference between deprecating and sunsetting an API endpoint?
Deprecating means callers should move off it, but it still works. Sunsetting is the date after which it is expected to stop answering. Removal is when the route is actually gone.
Which HTTP headers mark an endpoint as deprecated?
Deprecation (RFC 9745), with a date written as @ and Unix seconds, and Sunset (RFC 8594), with an HTTP-date for the expected end. Add a Link header with rel="deprecation" that points to the migration notes.
How long should a deprecation period be for an internal API?
Long enough for every consumer team to plan the work into a sprint and ship it, and for a full business cycle at zero traffic afterwards. Set it with the consumer teams’ replies in hand, not before.
How do I know it is safe to remove the endpoint?
Every listed consumer team has said it migrated, and the traffic to the endpoint has stayed at zero for a full business cycle, including a month end. The list alone is not enough: only traffic shows callers nobody listed.
Where does Graphwake fit when I retire an endpoint?
It answers who is affected: the teams subscribed to the endpoint. When the endpoint is removed from the spec, it alerts those teams and scores the removal.
Pick an endpoint. See who it reaches. 7-day free trial. Cancel before day 7 and you pay nothing.
Start free trialSources and last verified
- rfc-editor.org/rfc/rfc9745.html
- rfc-editor.org/rfc/rfc8594.html
- rfc-editor.org/rfc/rfc9110.html#name-410-gone
- spec.openapis.org/oas/v3.1.0.html#operation-object
Sources checked on 2026-11-09.