# Versioning and deprecation

Building on an API is a bet that what works today still works in six months. This page states exactly what can change without notice, what never changes without advance warning, and how you find out.

## The rule in one sentence

**`/api/v1` only grows.** Everything that responds today will keep responding the same way: if something has to break, it lives at `/api/v2` and both coexist for at least six months.

## Changes you can expect without notice

These are **additive**: they don't break anyone who is already integrated, and they happen often.

- New endpoints.
- New fields in a response.
- New optional parameters.
- New values in an enum field (a new status, a new channel type).
- New error codes within an existing `type`.

Two practical consequences for your integration:

1. **Don't assume you know every field in a response.** Ignore the ones you don't use instead of failing. The contract's schemas are marked as open for exactly this reason.
2. **Don't write an exhaustive `switch` over an enum without a default branch.** A new status shouldn't take down your process.

## Changes that never happen without a deprecation cycle

- Removing an endpoint.
- Removing or renaming a field in a response.
- Renaming a route or an `operationId`.
- Making an optional parameter required.
- Changing the meaning of a value that already existed.

Any of these goes through the full cycle below.

## The deprecation cycle

When an endpoint is going to be retired, four things happen **before** it stops responding:

1. **It's marked in the contract.** The operation carries `deprecated: true` in `openapi.public.json`, the retirement date in `x-sunset`, and what to use instead in `x-alternative`. If you generate your client from the contract, most generators mark the method as deprecated and your editor strikes it through.

2. **Every response tells you.** While it's still alive the endpoint responds normally — it doesn't fail, its body doesn't change — but it adds these headers:

   | Header | What it says |
   |---|---|
   | `Deprecation` | `true`. This endpoint is deprecated. |
   | `Sunset` | The date from which it stops responding, in HTTP format. |
   | `Link` | A link to this page, with the alternative in the `title`. |

   ```bash
   curl -i https://api.met.meteor.com.co/api/v1/... \
     -H "Authorization: Bearer met_live_your_key"
   # HTTP/1.1 200 OK
   # Deprecation: true
   # Sunset: Wed, 01 Jul 2026 00:00:00 GMT
   # Link: <https://developers.meteor.com.co/guias/versionado.html>; rel="deprecation"; type="text/html"; title="Usa POST /runs"
   ```

   If you have observability over your outbound calls, it's worth alerting when a `Deprecation` shows up — it's the cheapest way to not find out late.

3. **A [changelog](../../changelog.html) entry** explains why and what to migrate to.

4. **At least six months pass** between the announcement and the retirement.

## How to know which version you generated against

The contract declares its version in `info.version`, and that version is the same one heading the most recent [changelog](../../changelog.html) entry.

```bash
curl -s https://developers.meteor.com.co/public/openapi.public.json | jq .info.version
```

If you save that number the day you generate your client, comparing against the changelog tells you exactly what happened in between.

## What this cycle does not cover

- **Error `type` values are a closed list** of five and they don't grow: `authentication_error`, `invalid_request_error`, `rate_limit_error`, `agent_error`, `api_error`. The `code` values inside each one do grow. Program against the `type` when you need a control branch, and use the `code` for the message. It's all in [Errors, idempotency and pagination](errors-and-idempotency.html).
- **Your plan's limits are not an API contract.** The rate limit and the quota can change with your plan; read them from the headers on each response instead of assuming them. See [Limits and quotas](limits.html).
