Skip to main content
Three different things get versioned here, and they move independently. Keeping them apart is most of what this page is for. Minting a new operating point does not imply a new URL version. A repricing does not change a selection. A retune does not reprice anyone. Only a breaking change to the wire contract mints /v2.

URL versions are major-only

The only version identifiers that ever appear in a path are /v1, /v2, /v3. A minor or patch number never appears in a URL.
  • A breaking change is a major bump and gets a new URL version.
  • Patches and minor additions stay at the current URL version. A new optional response field, a new optional request field with a safe default, a new operating-point label, a bug fix, all ship at the existing /vN.

What counts as breaking

The test is the client’s, not ours: a change is breaking if a correct client written against the current contract stops working.
“Changing a default” in that table means a schema-level field default (for example, what records[].kind resolves to when omitted), not the operating point an unpinned request resolves to. Labels are themselves immutable and are never retargeted; what moves, by design and without a URL version bump, is which label the server’s default points at: see always pin it and the release notes entry for the most recent move. A client that pins budget.operating_point, as that page recommends, is unaffected either way.

Nothing is served unversioned

The version segment is an explicit route. A path outside a known version prefix matches nothing and is rejected before any of our code runs. There is no unversioned route and no implicit “latest”. Clients pin a URL version explicitly, exactly as they pin an operating point.

Two rules that keep your client working

These are the client’s side of the bargain. A client that ignores them will break on a change this contract considers non-breaking, and that will be the client’s bug, not a broken promise.
1

Ignore response fields you do not recognise

New optional fields ship within /v1. Strict schema validation that rejects unknown fields will fail on the next additive change. The first one already designed is the usage block.
2

Do not exhaustively match the gate outcome or its reason

Read the top-level outcome (engaged, stood_down, escalated) when you need to know what the service did. gate is not that signal: it reports the envelope gate’s shadow assessment, which runs at every published operating point without driving the result, so it can disagree with outcome on a perfectly healthy request. See branch on outcome.The gate assessment is an open, extensible enum. It takes a select value (gate.engaged: true) and a stand down value (gate.engaged: false), with the trigger carried in reason (engage:needle, standdown:high_drift, and others).The set is open. Values are added additively, as a new reason prefix or a new optional field, so a client that tolerates an unrecognised prefix keeps working across the change.Do not drive behaviour off a reason prefix. Branch on outcome, and treat gate.reason as something to log rather than to switch on. A client that switched on standdown: prefixes would discard successful selections, because the shadow assessment carries a standdown: reason on requests the service engaged on.

A version keeps serving until it is formally deprecated

Standing up /v2 is never, by itself, grounds for switching off /v1. Formal deprecation requires all of:
  1. A published deprecation notice naming the version, its replacement, and a sunset date.
  2. A migration path: what a caller must change, in writing.
  3. A notice period that has actually elapsed before removal, long enough that a pinned client is not broken by surprise.
Until every one of those is satisfied, the version keeps serving.
A URL version you pin stays pinned: it is not retired casually, and the operating points it can resolve stay frozen, so a call you cite today keeps resolving to the same configuration later. That is a promise about the settings behind the label, not about byte-identical output across engine builds; see what a label pins.

Changes you should expect at /v1

Additively, within this URL version:
  • The usage block on the response: the metering receipt. Additive and optional, which is why it does not mint /v2.
  • mode: "shadow" as a third value for budget.mode.
  • An escalate gate outcome, as described above.
  • New operating-point labels, whenever the engine is retuned or a new engine revision is published.
None of these will break a client that follows the two rules above. That is why the rules are stated before the changes.