Skip to main content
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:
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.

Changes that arrive without a new version

These changes are additive. We make them within /v1 and list them in the 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.

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 explains how to work with them.

Where changes are announced

Changes to the API are announced in the API changelog, newest first.