Guide
Deprecation policy
A published API is a promise. When Kelomo needs to retire part of it, you hear about it from the API itself — in the response headers and in the OpenAPI contract — long before anything stops working. Nothing in the v1 surface is deprecated today.
How much notice you get
| Change | Minimum notice | What happens |
|---|---|---|
| An operation is removed | 12 months |
It is marked deprecated, keeps working unchanged for the whole period, and answers
404 only after the sunset date.
|
| An operation changes behaviour (a field's meaning, a default, a narrower result set) | 6 months | The old behaviour stays until the sunset date; the new behaviour is documented in the reference from the day it is announced. |
| Something is added (a new operation, a new optional field, a new enum value in a response) | None | Additions are not breaking. Ignore fields you do not use and tolerate unknown enum values — that is what makes them safe. |
| A security or legal fix leaves no choice | As short as the risk demands | The exception, not the rule. You are told what changed, why, and what to do — and it is written into the change log like everything else. |
A deprecation always names a replacement — or states in writing that there is none and why. "Use something else, figure out what" is not an announcement we are allowed to make: the machinery that marks an operation deprecated refuses metadata without either.
What a deprecated operation sends back
Every response from a deprecated operation carries three headers. They are the standard ones, in their standard formats — worth reading carefully, because the two dates are encoded differently:
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: @1785974400
Sunset: Fri, 06 Aug 2027 00:00:00 GMT
Link: <https://kelomo.fi/developers/guides/deprecation/>; rel="deprecation"; type="text/html" -
Deprecation(RFC 9745) — the date the deprecation was announced, as a structured-field date:@followed by Unix seconds. It is not an HTTP-date. -
Sunset(RFC 8594) — the date the operation stops answering, as an IMF-fixdate (the same format as theDateheader). It is never earlier than the deprecation date. -
Linkwithrel="deprecation"— this page.
Operations that are not deprecated send none of these. The presence of the header is the signal; you do not have to parse anything to detect it.
Noticing it in your code
The cheapest integration health check there is: log the header once, in the wrapper every
call already goes through. A deprecation you find in a log six months early is a task; one
you find from a 404 is an incident.
// One check, in the layer every call already passes through.
async function kelomo(path, init) {
const response = await fetch(`https://api.kelomo.fi${path}`, init);
const deprecation = response.headers.get('Deprecation');
if (deprecation) {
// RFC 9745: a structured-field date — "@" plus Unix seconds.
const since = new Date(Number(deprecation.replace('@', '')) * 1000);
const sunset = response.headers.get('Sunset'); // RFC 8594 (HTTP-date)
console.warn(
`Kelomo: ${path} was deprecated on ${since.toISOString().slice(0, 10)}` +
(sunset ? `; it stops answering after ${sunset}` : ''),
);
}
return response;
} And in the contract
The same fact is in the OpenAPI document: the operation is marked
"deprecated": true, and its description states the announcement date, the sunset
date and the replacement. Most generators surface this automatically — a generated client
will warn you at compile time.
# Every deprecated operation is marked in the OpenAPI contract, with the
# sunset date and the replacement in its description.
curl -s https://kelomo.fi/developers/openapi.json \
| jq -r '.paths | to_entries[] | .key as $p | .value | to_entries[]
| select(.value.deprecated == true)
| "\(.key | ascii_upcase) \($p) — \(.value.description)"' Where the change log is
Every deliberate change to the published contract — including every deprecation and every sunset — is recorded in the API change log, and the API reference on this site is always generated from the current contract. A contract change cannot ship without that entry: the build compares the published surface against a committed baseline and refuses a silent removal, so the log and the API cannot drift apart.
What to do when you see a deprecation. Nothing urgent — that is the point of the notice period. Read the replacement in the operation's description, plan the move inside the sunset window, and keep calling the old operation until you have. It behaves exactly as it always has until the sunset date; it is not slowed, sampled or degraded in the meantime.
What about /v2?
The /v1 prefix is a version, not a release train. Additive changes ship inside
it continuously. A new major version is only for changes that cannot be expressed as a
deprecation with a replacement, and it would run alongside /v1 for the full
12-month notice — you would never be asked to migrate everything at once.