Skip to content

Versioning

The version is in the path: every endpoint lives under /external/v1.

Additive changes ship within v1. New fields on an existing response, new endpoints, new error codes, new enum members. These land without a version bump and without prior coordination.

So parse leniently: ignore fields you do not recognise, and do not use a strict schema validator that rejects unknown properties. A client that fails on an unexpected key will break on a change that was safe for everyone else.

Specifically, plan for:

  • New keys appearing in any object, including inside the full statement’s nested records.
  • New error codes. Match on the code you know and fall back to the HTTP status for anything else — the status is always meaningful even when the code is new to you.
  • New endpoints appearing in the reference.
  • No field is removed, and no field changes meaning. If a value’s definition needs to change, the new definition arrives as a new field.
  • No field changes type, including the integer-cents representation of money.
  • No path or operationId is renamed, so generated clients stay valid.
  • No existing error code is renamed or remapped to a different HTTP status.

That last set includes some specifics worth naming, because they are committed and can no longer be withdrawn inside v1: the tax identifiers on the discovery records (tax_id on a provider, ein on an entity); the ten error codes and the statuses they map to; the ten keys of the totals object, net_other_income_cents included; and the presentation hints carried by the full statement (title_tooltip, percentage_comment) — which you should ignore, but which are published and will keep arriving.

Anything not covered above lands as /external/v2. If that happens:

  • v1 is maintained in parallel — a v2 does not switch off v1.
  • The migration window is agreed with you in advance, not announced as a deadline.
  • We will not change the meaning of a v1 field to avoid cutting a v2.
  • Pin nothing but the major version. There is no minor version to track; /external/v1 is the whole contract.
  • Log unknown fields rather than failing on them. It gives you a cheap signal that something was added, without an outage.
  • Store the accounting_basis and the effective range alongside any figure you keep. Both are returned on every report for exactly this reason: a number without them is not reproducible later.
  • Treat this reference as the contract, not any document we have sent you. It is generated from a specification that lives beside the code and is checked against the running routes on every change, so it cannot quietly drift out of date.