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

# Versioning and compatibility

> What the /v1 path does and does not promise, and the one mechanism that tells you when a shape you parse moves.

Read this before you build something that has to keep working. It is short
because the honest answer is short, and it says what is undecided as plainly
as it says what is settled.

## There is one version, and it is the path

`/v1` is the prefix on the control plane's REST routes, and it is the whole of
the versioning scheme. A few paths sit outside it, and they carry no version in
their path at all:

* `/healthz`, which is the only tenant route left outside `/v1`;
* `/mcp`, the MCP transport, where the tool list is the contract;
* `/vrx/{runToken}/v1/...`, the worker surface a run hands out, whose `v1`
  comes after the run token;
* `/.well-known/oauth-protected-resource` and its `/mcp` variant.

The agent run routes used to be on that list, and that was the one open
question on this page. It was decided on 2026-09-20, in the window before the
launch, and the move has shipped: starting, reading, listing, pausing, resuming
and cancelling a run are `/v1/runs` and `/v1/runs/{runId}` now.
`GET /v1/runs/{runId}` also answers to the `agentRunId` that the old
`GET /runs/{agentRunId}` took, so a permalink has one route rather than two.
The old `/tasks` and `/runs` paths are not served at all: there is no alias and
no redirect, they answer `404`. That is a break, and it is one this page can
allow only because it happened **before** the 2026-09-25 baseline the freeze
policy below protects. Nothing moves that way after that date.

Every route in the published spec has a fingerprint, `/healthz` included, so a
shape change there is just as visible to you.

Four things follow from the path being the scheme, and each one is a fact
about the running server rather than a plan.

* **No version header selects a shape.** The server reads no request header
  that chooses between API versions, and one you invent is ignored. From a
  browser you cannot even send one: the preflight allow list for request
  headers is exactly `Authorization`, `Content-Type`, `x-phonebase-step-up`
  and `Idempotency-Key`.
* **No dated version to pin.** There is no `2026-01-01` style version to
  request and no account level pin behind it.
* **No `Deprecation`, `Sunset` or `Warning` response header.** Nothing in a
  response announces that a shape is on its way out. What you do get back is
  the rate limit budget (`RateLimit-Limit`, `RateLimit-Remaining`,
  `RateLimit-Reset`, `RateLimit-Policy`), `Retry-After`, and
  `WWW-Authenticate`. See [Rate limits](/api/rate-limits).
* **No `deprecated` marker in the spec.** Nothing in the published OpenAPI
  document is flagged as on its way out.

There has never been a `/v2`. The practical consequence is the one worth
stating out loud: **you cannot ask for an older shape.** When a response shape
changes, it changes for every caller at the same moment.

<Note>
  The OpenAPI document carries an `info.version` field. It tracks the package
  that generates the document and it is not something you can request, so do
  not read it as a compatibility signal. The fingerprints below are the signal.
</Note>

## Pin the shape you parse

This is the part to act on, and it works today.

Every operation in the published spec has a fingerprint: a digest over the
part of that operation your code can break on. Parameters, request body,
the set of response status codes and each one's schema, response header names,
security, and the `x-phonebase` extensions all go in. Prose is excluded at
every level, so rewording a description never moves a digest.

The digests are published as a single file next to the spec:

```bash theme={null}
curl -sS https://docs.phoneuse.com/api/contract-fingerprints.json
```

It needs no credential. Fetch it in your own CI, compare it against the
digests you recorded when you wrote the parsing code, and fail your build when
one of them moves. A digest that moved means the shape you parse moved,
whether or not anybody remembered to tell you.

That check runs in your pipeline, on your schedule, against an artifact you
fetched yourself. It is the strongest thing on this page for exactly that
reason.

<Warning>
  **A fingerprint sees shape, and it cannot see meaning.** A field that keeps
  its name and its type while changing what it counts moves no digest. Neither
  does a field the spec never declared. Treat the fingerprints as an alarm on
  structure, and read the [changelog](/changelog) and the generated
  [API reference](/api) for the rest.
</Warning>

The spec those digests are computed from is itself generated from the route
table the server runs, so it describes the surface rather than somebody's
account of the surface.

## The MCP tool surface has its own rule

The tool surface an agent drives is frozen from the launch on 2026-09-25 and
evolves under a published program from then on. New tools, new optional
parameters and new error codes are allowed. Renames and removals are not: a
tool keeps its name and gains meaning, and there is no `tap_v2` family. A
change that would break an existing caller goes through the deprecation
program below first.

Two things make that checkable from the outside. The server reports a tool
surface version in the `serverInfo` a client reads at connect time, so a
client can tell one published surface from another. And a parameter or field
added after the frozen baseline carries an `@since` marker you can read in the
[tool reference](/mcp/reference).

Read [MCP surface](/mcp/overview#the-surface-is-a-frozen-contract) for the
full statement of that contract.

## After launch, additive only

This is the policy for `/v1` and for the MCP tool surface from the launch on
**2026-09-25** onward. Before that date shapes under `/v1` changed in ways that
required a caller to change with them, without notice. One example is on the
receipt shape: `leaseId` and `fencingToken` were removed from it, because a
read only credential could lift a live lease off the newest receipt and hand
it to one that can act. The surface published on the launch date is the
baseline this policy protects.

Every change after launch falls into one of three tiers, and the tier decides
what has to happen before it ships.

1. **Additive.** A new operation or tool, a new optional parameter, a new
   response field, a new error code. Allowed at any time with no notice,
   because a caller that ignores what it does not recognise keeps working.
   Parse responses that way: ignore fields you do not know.
2. **Meaning changes, shape does not.** A field keeps its name and type and
   what it tells you gets stricter. This is declared rather than versioned: the
   change is written into the [changelog](/changelog), and on the MCP surface
   the tool description carries an `@since` note.
3. **Breaking.** A rename, a removal, a new required parameter, or an optional
   field made required. This goes through a deprecation program. The change is
   announced in the [changelog](/changelog) with the date it takes effect, the
   old shape keeps being served for at least one release cycle after the
   announcement, and a field on its way out keeps being accepted and returned
   during that time rather than refused. On the MCP surface the result carries
   a deprecation warning, and the removal ships with a version bump in the
   `serverInfo` a client reads at connect time.

For an HTTP operation on its way out, the announcement also travels in the
response itself: a `Deprecation` header ([RFC 9745](https://www.rfc-editor.org/rfc/rfc9745))
from the day the removal is announced, and a `Sunset` header
([RFC 8594](https://www.rfc-editor.org/rfc/rfc8594)) carrying the date it stops
being served. Nothing is deprecated today, so no response carries either header
yet, which is what the list at the top of this page says.

The changelog entries for these surfaces are not written from memory. Each
docs publish compares the contract fingerprints and the MCP tool names against
the previous publish and adds a dated entry listing what was added, what
changed shape, what was removed, and what was renamed. A rename is only
reported as one when the change that made it says so; otherwise it shows up as
a removal and an addition, which is what it looks like to your parser.

Two mechanisms back this up on our side. Every `/v1` operation, and `/healthz`
outside it, has a registered set of known readers, and a change that moves an operation's
fingerprint fails our build until each reader has been re-confirmed against the
new digest. And the fingerprints are published, so you can **pin them** and see
a shape move in your own pipeline whether or not the notice reached you. That
is why that section comes before this one.

## Where to go next

<CardGroup cols={2}>
  <Card title="Changelog" href="/changelog" icon="clock-rotate-left">
    What changed, and the rule that decides whether an entry may appear there.
  </Card>

  <Card title="API reference" href="/api" icon="code">
    The two HTTP surfaces and the boundary between them.
  </Card>

  <Card title="Rate limits" href="/api/rate-limits" icon="gauge-high">
    The budget headers, and what to do when one runs out.
  </Card>

  <Card title="MCP surface" href="/mcp/overview" icon="wrench">
    The tool surface, and the contract that keeps it stable.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.