> ## Documentation Index
> Fetch the complete documentation index at: https://docs.get-exo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Versioning and stability

> Everything inside /v1 evolves additively, no shipped route is ever renamed, and a retirement is announced on the wire before it happens.

**One rule covers almost everything: `/v1` only grows. No shipped route is renamed, no response field is removed, and no existing field changes meaning.**

That is not a soft promise. Every client already in the field, including the Exo CLI, the MCP server and the design partners' own integrations, depends on it, which is why the contract is curated rather than dumped from whatever the code happens to expose this week.

## What is a breaking change, and what is not

| Change                                     | Breaking | Why                                                                              |
| ------------------------------------------ | -------- | -------------------------------------------------------------------------------- |
| A new optional request field               | No       | Omit it and behaviour is unchanged.                                              |
| A new field inside a response object       | No       | Read tolerantly and ignore what you do not know.                                 |
| A new value in a string-typed status       | No       | Statuses are documented as strings, not closed enums, precisely so this is safe. |
| A new route, or a new error code           | No       | Handle unknown codes by status class.                                            |
| Renaming a route or a field                | **Yes**  | Does not happen inside `/v1`.                                                    |
| Removing a response field                  | **Yes**  | Does not happen inside `/v1`.                                                    |
| Tightening validation on an existing field | **Yes**  | Does not happen inside `/v1`.                                                    |

One thing follows from this and is worth building in from the start: **write a tolerant reader.** New keys will appear inside objects you already parse. A client that rejects unknown fields is a client a purely additive change can still break.

## There is no version switcher

You will not find a version dropdown on this site. Shipping one would advertise a churn that does not exist: there is one version, it is `/v1`, and the point of the additive rule is that you never have to migrate off it.

Nor is there a date-pinned version header. The base URL is the version.

```
https://api.get-exo.com/v1/...
```

## When something is retired

Retirement is announced on the wire, on every response from the affected route, not only in a changelog nobody polls. Three standard headers carry it.

```http theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
HTTP/1.1 200 OK
Deprecation: @1767225600
Sunset: Wed, 01 Jul 2026 00:00:00 GMT
Link: <https://api.get-exo.com/v1/new-thing>; rel="successor-version"
```

| Header        | Standard | What it says                                                                                                                                              |
| ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Deprecation` | RFC 9745 | When the route became deprecated, as an `@` followed by whole seconds since the Unix epoch. A future value is legal and means it becomes deprecated then. |
| `Sunset`      | RFC 8594 | An HTTP-date naming the moment the route is expected to stop responding.                                                                                  |
| `Link`        | RFC 5829 | `rel="successor-version"` points at the replacement route. `rel="deprecation"` may point at a human-readable notice.                                      |

The same declaration also flips that operation's `deprecated` flag in the OpenAPI document, so the published contract and the live response can never disagree. If you generate a client, the deprecation reaches your code without anyone reading a release note.

**No route carries these headers today.** This is the mechanism, published in advance so a client can be written against it now rather than in a hurry later.

## Detecting a deprecation

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  curl -sS -D - -o /dev/null https://api.get-exo.com/v1/me \
    -H "X-Exo-API-Key: $EXO_KEY" \
    | grep -iE '^(deprecation|sunset|link):'
  ```

  ```python Python theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  import logging
  import httpx

  response = httpx.get(
      "https://api.get-exo.com/v1/me",
      headers={"X-Exo-API-Key": EXO_KEY},
  )

  if "Deprecation" in response.headers:
      logging.warning(
          "route deprecated: sunset=%s successor=%s",
          response.headers.get("Sunset"),
          response.headers.get("Link"),
      )
  ```

  ```typescript TypeScript theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
  const response = await fetch("https://api.get-exo.com/v1/me", {
    headers: { "X-Exo-API-Key": process.env.EXO_KEY! },
  });

  const deprecation = response.headers.get("Deprecation");
  if (deprecation) {
    console.warn("route deprecated", {
      sunset: response.headers.get("Sunset"),
      successor: response.headers.get("Link"),
    });
  }
  ```
</CodeGroup>

Logging a warning when `Deprecation` appears costs three lines and is the whole migration early-warning system.

## The contract is the specification

The OpenAPI 3.1 document behind this reference is the source of truth, and it is curated rather than dumped: 64 paths, 80 operations, 135 named schemas, plus an `x-exo-concepts` index naming the objects that make Exo different from a vector store.

Generate a client from it, diff it between releases, or check it into your own repository as the thing your integration is written against. See [Clients and SDKs](/platform/sdks).

## Capabilities that will grow

Some parts of the surface are honestly narrower today than they will be. These are additive gaps, not planned breaks:

* **Connectors** support `github` and nothing else.
* **Exports** produce `json` and nothing else. The field is a constant in the contract, not an open enum.
* **Contradictions** always come back `status: "open"`, because no resolution lifecycle is stored yet.
* **The SSE stream does not replay.** `Last-Event-ID` is accepted so resuming clients do not error, and is then ignored.
* **`AgentFailurePattern`** is a named object in the contract; the team insights route that would serve it is not in v1.

Each of these grows by adding, not by changing what already works.

## Next

<Columns cols={2}>
  <Card title="Errors" icon="triangle-alert" href="/platform/errors">
    Why an unknown error code is safe to handle by status class.
  </Card>

  <Card title="Clients and SDKs" icon="package" href="/platform/sdks">
    There is no published package yet. Here is what to generate from instead.
  </Card>
</Columns>
