Every API deprecation is a promise you're allowed to break exactly once — and only if everyone hears about it before you do. Small teams fail at this in two symmetrical ways: never deprecating anything (four versions alive, every bug exists four times), or deprecating with a changelog entry nobody reads and a deadline nobody believed. The full template with the sunset timeline is on our ops notes. Here's the core.
Three notices, one message
Each channel reaches a different person:
- The changelog entry (T−90): what's deprecated, the sunset date, the replacement, the migration note — linked from every affected endpoint's docs page.
-
The runtime warning:
DeprecationandSunsetheaders on every response from the old version, from day one of the notice period. This is the one small teams skip and the one that works: a warning in the customer's own logs reaches the person whose code will break, even if they never read anything you send. - The direct email (T−60): sent only to accounts that actually called the old version in the last 30 days, with a named engineer on reply duty.
One line of middleware is worth fifty emails.
The sunset timeline
| Clock | What happens |
|---|---|
| T−90 | Changelog + headers live + first email. Gate: the replacement already works. Deprecating before the replacement is real isn't deprecating — it's breaking. |
| T−60 | Usage dashboard review: who is still calling? Migration guide with copy-paste diffs. |
| T−30 | Second email to remaining callers, with their own usage counts in the body: "your account made 41,000 calls to v1 last week." |
| T−7 | Final notice; decide the fallback: hard stop or read-only grace window — a decision, not an improvisation. |
| T−0 | The endpoint returns 410 Gone with a JSON body naming the replacement — never a naked 404. Watch the 410s all day; a spike is someone who needs help. |
| T+7 | Deprecation review: who migrated, how long it took, what the next timeline should be. |
Ninety days is the small-team standard: long enough to fit inside a customer's release cycle, short enough that the old version doesn't become permanent. The only legitimate extension is a documented one with a new date — the quiet indefinite extension is how dead versions survive forever.
The holdout ladder runs on usage, not email opens
Rank the remaining callers by real call volume. The ten loudest are your whole migration — handle them personally. Accounts making three calls a month are usually forgotten cron jobs, not customers; the guide link inside the 410 body is their fix. And the zero-warning rule: if T−0 arrives for an account that never saw a header or an email, that's your incident, not their fault. Extend their window and say so out loud.
The email itself: five sentences
- What is going away — exact version and endpoints, not "some legacy endpoints."
- When — one calendar date. "Early next quarter" is not a date; it's a shrug.
- Why — one honest sentence. Customers accept reasons; they don't accept silence.
- What to do — replacement endpoint + migration guide, with the old-vs-new diff shown, not described.
- A human to reply to.
Subject line that works: "Action needed: v1 API sunsets March 31 — your migration guide." Anything starting "We're excited to announce…" doesn't.
The mistakes that turn a sunset into an outage
Changelog-only announcement (a legal fig leaf, not communication), deprecating before the replacement has documentation, the naked 404, "early next quarter," and sunset-day silence — reading about the churn in a review instead of watching the 410 dashboard.
The full version — including the versioning habits that make the next deprecation boring — is in the template. For the unplanned breakages, the Ops Starter Kit ($14) turns first-30-minutes chaos into a fillable plan, and Vol. 2 ($27) adds the DR plan and evidence log. The free First 30 Minutes checklist is the taste test.
Top comments (0)