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

# Versioning and changes

> How the Surfais API is versioned, which changes arrive without a new version, and how to build a client that keeps working.

The Surfais API changes in two ways. Additive changes arrive within the current version, and a well-built client needs no change. Breaking changes ship as a new version. This page says which is which, and how to write a client that takes additive changes in its stride.

## The version is in the URL

Every endpoint sits under one base URL, and the version is part of it:

```text theme={null}
https://api.surfais.com/v1
```

`v1` is the only version today. There is no version header and no version parameter: the path decides.

Webhook events state the version as well. Every event body carries `"api_version": "v1"`, so a receiver can tell which version of the payload it is reading. See [Webhook events](/api/webhooks/events).

## Changes that arrive without a new version

These changes are additive. We make them within `/v1` and list them in the [API changelog](/api/changelog):

* a new endpoint;
* a new optional query parameter, or a new optional field in a request body;
* a new field in a response or in a webhook payload;
* a new webhook event type;
* a new `error.code`, or a new code inside an error's `details`;
* a new value in an enumerated field — for example a new `action` in a prompt sync result, or a new `source` on a prompt.

## Build a tolerant client

Write your client so that an additive change cannot break it. Four habits do that.

* **Ignore fields you do not know.** Read the fields you use and let the rest pass. Do not validate a response or a webhook body against a closed list of fields.
* **Give every switch a default branch.** Do not match enumerated values, `error.code` values or `details` codes exhaustively. Treat a value you do not recognise as "other", not as a failure of your parser. When you meet an `error.code` you do not know, fall back on the HTTP status to decide what to do.
* **Treat identifiers as opaque strings.** Ids, pagination cursors, `score_version` and `panel_version` are strings to store and to send back unchanged. Do not parse them, do not assume a length or a pattern, and do not try to order them.
* **Branch on the error code, never on the message.** `error.code` is the stable, machine-readable value. `error.message` is written for people, and its wording can change. See [Errors](/api/errors).

## Breaking changes

Removing or renaming a field, or changing a field’s type or what it means, is a breaking change. Changes like these ship under a new version path rather than in `/v1`.

## Data versions are not API versions

Two fields have "version" in their name and describe the **data**, not the API:

* `score_version` names the scoring model that produced a score.
* `panel_version` names the measurement panel — the set of AI models — that produced a measurement.

You meet both on score points, in the brand summary and on share of voice. `score_version` also appears in the `score.threshold_crossed` webhook event. Either can be `null`. Compare two scores only when they share a `panel_version` and, for the AIS Score, a `score_version`.

When one of these values changes, the measurement has changed. The API has not: the same fields arrive, with the same types, from the same endpoints. Treat both as opaque strings, as described above. [The data model](/api/data-model) explains how to work with them.

## Where changes are announced

Changes to the API are announced in the [API changelog](/api/changelog), newest first.
