# Versioning

> How the /v1 path, the Refabric-Version header and deprecation notices keep your integration working while the API changes.

## Three layers

| Layer | Example | Changes when |
|---|---|---|
| **Major version** in the path | `/v1` | a change so wide it affects the whole API (rare; announced long in advance) |
| **Dated version** header | `Refabric-Version: 2026-09-29` | a small breaking change to shared behaviour (headers, error shapes, envelopes) |
| **Task name** | `image.glam` → `image.glam.v2` | a breaking change to one task's inputs or outputs |

## What is breaking

Breaking (never done without a new version):

- removing or renaming an endpoint, field, header or task;
- adding a **required** input field, or making an optional one required;
- removing an accepted input value or narrowing a limit;
- changing the type or meaning of a field;
- changing an error `code` for the same situation;
- changing authentication or signature format.

Not breaking (can happen any day — write your client to tolerate it):

- adding endpoints, tasks, optional input fields, response fields, headers;
- adding values to **output** enums (job statuses, error types, codes) — see
  [Conventions](https://docs.refabric.com/api-reference/platform/conventions#enums);
- adding input values or relaxing a limit;
- rewording `message` texts and documentation;
- changing the order of object keys, or the length of opaque ids and cursors.

## `Refabric-Version`

```http
Refabric-Version: 2026-09-29
```

- The current version is `2026-09-29`; send it to pin it.
- A date names a snapshot of shared behaviour. Without the header you get the version pinned to
  your account (by default, the version current when your first key was created).
- Responses echo the version used in `Refabric-Version`.
- Each dated change is listed in the [changelog](https://docs.refabric.com/changelog) with the migration step.

## Deprecation and sunset

A task that is going away is first **deprecated**: it keeps working exactly as before, and you are
told in two places.

1. **The catalogue.** Its entry in `GET /v1/tasks` and `GET /v1/tasks/{name}` carries
   `"status": "deprecated"`. Nothing else in the entry changes, and an entry without `status` is
   current.
2. **The changelog.** The same day, the [changelog](https://docs.refabric.com/changelog) lists it on a `Deprecated:` line
   with its replacement (usually the next version of its name, `image.glam` → `image.glam.v2`) and a
   `Migration:` step. A task is never marked deprecated without that entry.
3. **An e-mail.** Once a week, the owner of every API key that started a deprecated task in the
   last days gets one e-mail naming those tasks and keys, until the calls stop or the
   task is removed.

Then:

4. Removal is a **Breaking** `Removed:` entry in the changelog; after it the task is no longer in
   `GET /v1/tasks`, and every call naming it (`GET /v1/tasks/{name}`, `/estimate`, a submit)
   answers **`410 task_removed`** — not `404`, so a client can tell "gone" from "misspelt".

Deprecations are announced in the catalogue and the changelog. Check the catalogue:

```python
for task in s.get(f"{API}/tasks").json()["items"]:
    if task.get("status") == "deprecated":
        log.warning("Refabric task %s is deprecated — see the changelog", task["name"])
```
