# Deprecation policy

How long a deprecated route keeps working, what we consider breaking, and which headers tell you an endpoint is on its way out.

This page is the commitment behind every `Deprecation` header the API sends: how
much notice you get, how to find out which of your calls are affected, and what
we will and won't change without one.

## The commitment

**A deprecated route keeps working for at least 30 days after we announce it**,
and every announcement carries a date. That minimum is in the
[Terms of Service](https://beel.es/terminos), which reserve the right to change,
deprecate or remove endpoints only with at least 30 days' notice — the sole
exception being a security emergency.

Thirty days is the floor, not the plan. The current deprecation has run longer,
and we never bring a published `Sunset` date forward: if we get it wrong, it
moves later, never sooner. Nothing is removed quietly.

## How you find out

Every deprecated operation answers with three headers. They're on the response
to your normal calls — you don't have to poll anything:

| Header | Value | What it tells you |
| --- | --- | --- |
| `Deprecation` | `true` | This route is on its way out. |
| `Sunset` | An HTTP date | The day it stops answering. |
| `Link` | `rel="successor-version"` | The path to call instead. |
| `Link` | `rel="deprecation"` | The guide explaining what changes when you switch. |

A single response carries both `Link` relations, comma-separated:

```http
HTTP/1.1 200 OK
Deprecation: true
Sunset: Thu, 10 Sep 2026 00:00:00 GMT
Link: </v1/companies/{company_id}/customers>; rel="successor-version",
      <https://docs.beel.es/changelog/resources-under-the-nif>; rel="deprecation"
```

All four are exposed via `Access-Control-Expose-Headers`, so a browser client
can read them too.

<Callout type="info">
  **The fastest audit is your own logs.** Grep a day of API responses for
  `Deprecation: true` and you have the exact list of calls you need to change —
  no guessing from the reference, no reading a changelog end to end.
</Callout>

### When there is no successor

Some routes have no drop-in replacement, and we say so instead of pointing you
somewhere that behaves differently. Those answer `Deprecation` and `Sunset` but
**no `rel="successor-version"`** — the migration guide is still linked, because
that's where the difference is explained.

The current examples are the `PUT`s that *replace* a resource
(`PUT /v1/customers/{customer_id}`, `PUT /v1/products/{product_id}`,
`PUT /v1/recurring-invoices/{recurring_invoice_id}` and
`PUT /v1/configuration/series/{series_id}`). The canonical surface has a single update verb,
`PATCH`, and it *merges*: a field you leave out is kept rather than cleared.
Moving one of those calls without reading it changes what it does.

## What counts as breaking

We treat these as breaking, and they only ship with notice and a date:

- Removing an endpoint, a field, or an enum value.
- Renaming anything in a request or response.
- Making an optional request field required, or narrowing what a field accepts.
- Changing the type or the meaning of a field.
- Turning a status code that indicated success into one that indicates failure.

These are **not** breaking, and ship without notice — write your client so they
don't hurt:

- Adding a new endpoint, a new optional request field, or a new response field.
- Adding a new enum value to a field the API *sends*.
- Adding a new error code within a status code you already handle.
- Changing the wording of a human-readable `detail` message.

<Callout type="warn">
  **Ignore response fields you don't know.** New fields appear in existing
  responses without notice; a client that rejects unknown properties will break
  on a change that is, by this policy, additive.
</Callout>

## Deprecations in flight

**Flat routes move under the NIF** — the flat resource routes
(`/v1/invoices`, `/v1/customers`, `/v1/products`,
`/v1/recurring-invoices` and friends) are deprecated in favour of their
company-scoped equivalents. They retire on **9 December 2026**.

The full route-by-route table, what breaks, and how to hand the job to Claude
Code are in [Resources under the NIF](/changelog/resources-under-the-nif).

## Related

<Related>

- [Changelog](/changelog) — every change, breaking or not, as it ships
- [Handling errors](/guides/handling-errors) — the error shape your client already parses

</Related>

---

Full OpenAPI spec: https://docs.beel.es/api/openapi