Article

Data vendor notice periods for breaking schema changes and API deprecation

A breaking change in a data feed reaches you through a version, a header or a changelog, and the notice period sets how long you have to move. What breaks a pipeline, what to put in the contract, and a test for every delivery.

11 min read

A data vendor's notice period for a breaking schema change is the time between the announcement and the day the old shape of the data stops arriving. This post sets out which changes break a pipeline and which do not, how notice reaches you through versions, the IETF Deprecation and Sunset headers and a changelog, and what to ask a vendor to put in writing, with a test to run on every delivery and how we version our own API, labels and scores.

What notice period should a data vendor give before a breaking schema change or API deprecation?

We found no IETF standard that fixes the length. The IETF headers for deprecation and sunset carry dates, not a minimum, so the period is each vendor's own policy and belongs in your contract. Ask for it in days, counted from the announcement, with the old version delivered unchanged until it ends, and plan your migration against it.

GitHub's REST API documentation says that when a new version is released, the previous one is supported for at least 24 more months, and it lists exceptions for security and reliability issues and very low-usage services. Google's Cloud terms of service commit it to notify a customer at least 12 months before it discontinues a service without a materially similar replacement or significantly modifies a customer-facing API in a backwards-incompatible manner. The clause states exceptions, among them changes required by law or by a material security risk, and it does not cover some services, among them those before general availability.

For a data feed, two points follow. The clock starts at the announcement, so the channel matters as much as the length. And ask which exceptions your vendor keeps.

What counts as a breaking change in a data feed

A change breaks a pipeline when code written for the old delivery fails on the new one, or keeps running and returns wrong answers. Loud breaks are structural: a column removed, renamed or retyped. Silent breaks change the content under an unchanged shape: a new meaning, a new label version, a new code value.

GitHub's API documentation sorts changes into breaking and additive. Removing or renaming a response field, changing the type of a field and removing enum values are breaking; adding a response field and adding enum values are additive. Apache Avro applies the same logic when it reads a record. Its specification matches fields by name, ignores a field the writer has and the reader lacks, fills a field the reader expects from the field's default value, and signals an error when that field has no default. It also allows an int to be read as a long, float or double.

Change in the deliveryBreaks a pipeline?How to guard against it
A column or field addedNot when the reader ignores what it does not know; yes for a load that maps columns by positionMap columns by name and ignore unknown fields
A column removedYes, at the first query that names itCheck the required columns before the load
A column renamedYes: it arrives as one column removed and another addedThe same check, and a map of old to new names
A type changedYes, unless the change only widens the typeCompare delivered types with expected types
A new required fieldYes, for anything that reads older recordsAsk for new fields to arrive optional
A value added to a list of codesNot in structure; a mapping or an accepted-values rule drops or rejects itRoute unknown codes to a named bucket and alert
A value removed from a list of codesYes, for filters and joins on that valueAccepted-values tests on both sides
A column moved to another positionYes, for loads by positionLoad by header name
A constraint relaxed, so a column may now be emptyOften silent: counts and joins shiftA check on each column's share of empty values
A meaning changed under the same name and typeYes, silently: no schema check sees itA new name or version for every new meaning, in writing
A label version changedShares and counts can move at the boundaryKeep the version on every row and compare across it
An endpoint or path version retiredYes, on the sunset dateRead the Deprecation and Sunset headers and the changelog

Schema versioning best practices that keep a data vendor's changes from breaking your pipeline

Split changes into two lanes. Additions may arrive within a version, so your loader ignores unknown fields and maps columns by name. A removal, a rename, a new type or a new meaning ships under a new version name, delivered beside the old one through the notice period, and the version travels on every row.

Warehouses support the first lane. Snowflake's table schema evolution adds new columns during a load and drops the NOT NULL constraint from columns missing in new files, once the table has schema evolution enabled, the COPY INTO statement matches by column name and the loading role holds the EVOLVE SCHEMA or OWNERSHIP privilege. In BigQuery, columns added to an existing table must be NULLABLE or REPEATED, always go at the end of the schema, and can arrive with a load or an append through the ALLOW_FIELD_ADDITION option.

Both are switches: adding columns on arrival suits a raw landing table, while a modelled table should change only through your own reviewed code.

The second lane rests on three habits. Keep the version name with every row you load; the entry on label versions covers two versions in one table. Keep the changelog entry or the data manifest with each load. And hold the vendor to one rule: a meaning never changes in place, because a measure redefined under its old name is the change no schema check catches.

API schema versioning and backward compatibility: the contract data providers publish

A data provider's API contract has three parts: where the version is named, what may change inside a version, and how long an old version lasts after a new one is announced. Backward compatibility means a client built for the old version keeps working; additive changes keep it, and removals, renames and new types end it.

The version is named in the path, as in a URL ending in v1, or in a header. GitHub uses a request header, X-GitHub-Api-Version, with a date as the version name, and a request without the header is served the default version. Either form works when your client names the version explicitly and your logs record it.

The Deprecation and Sunset headers

Two IETF documents let an API announce the end of a resource in its own responses. RFC 9745, a Proposed Standard published in March 2025, defines the Deprecation response header. Its value is a structured date: an @ followed by a count of seconds from 1 January 1970 UTC, as RFC 9651 defines it. The date may be in the future, when the resource will be deprecated, or in the past, when it already was. Deprecation changes nothing about how the resource behaves, and a link with the deprecation relation points to documentation, written for people, about it.

RFC 8594 is an Informational RFC of May 2019, outside the standards track. It defines the Sunset response header, an HTTP date at which the resource is likely to become unresponsive. Clients should treat the date as a hint, not a guarantee, and a date in the past is safest read as the present. A link with the sunset relation points to the retirement policy. RFC 9745 ties the two together: the sunset time must not be earlier than the deprecation time.

HTTP/1.1 200 OK
Deprecation: @1798761600
Sunset: Thu, 01 Jul 2027 00:00:00 GMT
Link: <https://vendor.example/changelog/v1>; rel="deprecation"; type="text/html"

Received in late 2026, this response says the resource will be deprecated at midnight UTC on 1 January 2027, still behaves as before, and is likely to stop answering on 1 July 2027. GitHub's documentation describes both headers for an API version that is closing down.

Log every Deprecation and Sunset value your client receives, and alert on the first. A bulk file carries no response header, so a file delivery needs the same dates in a changelog and in the manifest of each package.

Schema evolution in vendor pipelines: data contracts, a schema registry and backward compatibility

A data contract is the schema, meanings and change rules agreed between a producer and its consumers. A schema registry enforces one: each new schema version is checked against a compatibility rule before it is accepted. A vendor runs the producer, so you keep the contract and test each delivery against it.

The documentation of AWS Glue Schema Registry lists eight compatibility modes, NONE, DISABLED, BACKWARD, BACKWARD_ALL, FORWARD, FORWARD_ALL, FULL and FULL_ALL, and recommends BACKWARD, under which consumers can read both the current and the previous schema version. Under BACKWARD, deleting a field or adding an optional one registers, and adding a required field is refused, because consumers on the new version could not read older records that lack it. The modes ending in ALL check against every earlier version, not only the last.

For a vendor feed, backward compatibility across the notice period means your current code reads both the old and the new delivery, which is what a parallel run needs.

Best practices for a data vendor contract on breaking schema changes and notice

A data vendor contract should fix five things: what counts as a breaking change, the notice period in days from the announcement, the channel that carries notice, a span when old and new versions arrive side by side, and the rule that a new meaning gets a new name. Ask how exceptions are announced too.

The clauses:

  1. A definition of breaking. Attach the list: a removal, a rename, a type change, a new required field, a removed code value, a change of meaning or of label version. Name additions as non-breaking.
  2. The notice period. In days from the announcement, for the API and for files if the two differ.
  3. The channel. A public changelog, an email to named technical contacts, and on the API the Deprecation and Sunset headers.
  4. The overlap. Old and new delivered side by side for the whole period.
  5. Names for meanings. A changed definition gets a new version or identifier, and rows already delivered stay as they were.
  6. Exceptions. Which events may shorten the period, and how you are told.
  7. A sample first. The new version on the companies you track, before the old one ends.

These terms sit beside the licence, and what a data licence covers sets out the uses a licence grants. Question 10 of our ten questions for a company data vendor asks the same in a vendor review.

Worked example: planning a migration inside a 90-day notice period

This example is illustrative. Acme Robotics is an invented company that licenses a vendor's job postings feed and serves a hiring dashboard from it.

Assumptions:

  • On Monday 12 October 2026 the vendor announces that the job function label moves to a new label version, with 90 days' notice, and delivers old and new labels side by side until the notice ends.
  • Mapping the new label values to Acme Robotics' dashboard categories takes 7 days.
  • A parallel run of four weekly loads, 28 days, compares the two versions.
  • Downstream owners need 14 days to sign off.
  • Acme Robotics freezes production changes for 14 days, from Monday 21 December 2026 to Sunday 3 January 2027, and keeps the whole migration on one side of it.

The working:

  1. The notice ends 90 days after 12 October: 19 days to 31 October, 49 to 30 November, 80 to 31 December and 90 on Sunday 10 January 2027.
  2. The work runs in sequence: 7 + 28 + 14 = 49 days.
  3. After the freeze, 4 to 10 January leaves 7 days, fewer than 49, so the switch has to land before the freeze begins on 21 December.
  4. From 12 October to 21 December is 70 days: 19 in October, 30 in November and 21 in December.
  5. The latest start is 49 days before 21 December: Monday 2 November 2026.
  6. The slack is 70 minus 49, which is 21 days.

Of the 90 days, three weeks are slack. The usable notice was set by Acme Robotics' own calendar, not by the vendor's date, which is why the overlap and a written date matter as much as the length.

A test to run on each delivery before it loads

Land each delivery in a staging table and run three checks before it loads further. Each query should return no rows, and a row stops the load. They are written for Job Postings, delivered in the Hiring product, and follow the data dictionary.

First, the columns your pipeline needs and their expected types, kept in a contract table of your own, compared with what arrived.

select c.column_name,
       c.expected_type,
       i.data_type as delivered_type
from feed_contract c
left join information_schema.columns i
  on  lower(i.table_name)  = 'job_postings_stage'
  and lower(i.column_name) = c.column_name
where i.column_name is null
   or lower(i.data_type) <> c.expected_type;

Second, label versions in the delivery that your mapping has not been built for, listed in a second table of your own.

select s.label_version, count(*) as postings
from job_postings_stage s
left join mapped_versions m
  on m.label_version = s.label_version
where m.label_version is null
group by s.label_version;

Third, values outside the documented list. The work mode of a posting is onsite, hybrid, remote or empty, so anything else is new.

select work_mode, count(*) as postings
from job_postings_stage
where work_mode not in ('onsite', 'hybrid', 'remote', '')
group by work_mode;

A new label version in the second check is the expected result of a notice: add it to your mapped versions once the mapping is done. For silent changes, add a fourth check that compares each column's share of empty values and the row count with the previous load.

How we version the Fokals API, labels and scores

Our API reference and methodology state the policy, and it follows the two lanes above.

  • The API. The path carries the version, v1. Within a version, fields and endpoints are added as they are released, so a client should ignore fields it does not know, and every documented field and endpoint stays, with its name and its meaning. A change that would break a client goes into a new version, and the old one stays for at least six months after the new one is announced in the API reference.
  • Labels and scores. Each row carries the name of its version. A change of meaning is released under a new version, with at least 90 days' notice for breaking changes.
  • Market Series. A change to a metric's definition is a new metric identifier, never a rewrite.
  • The record. Daily and weekly rows are written once after the period closes and never revised. Why we write each table once sets out the rules.
  • Where changes are listed. The methodology names each version with the date it began, and its changelog lists additions to the technology and software catalogues and the changes that need no new version. A bulk export package comes with a manifest naming the period, the versions and the licence.

Frequently asked questions

What is the difference between API deprecation and sunset?

Deprecation marks a resource as deprecated from a date and changes nothing about how it behaves. Sunset is the time the resource is likely to become unresponsive. RFC 9745, a Proposed Standard, defines the Deprecation header, and RFC 8594, an Informational RFC, defines the Sunset header. RFC 9745 requires the sunset time to be no earlier than the deprecation time.

Is adding a column a breaking change?

Not for a reader built to ignore what it does not know, and GitHub's REST API documentation lists adding a response field as an additive change. It does break a load that maps columns by position, or one that checks the column list for an exact match. Map columns by name and accept unknown fields in the landing table, and an added column passes without a change to your code.

Does a new label version count as a breaking change?

It can, even when every column keeps its name and type, because the same record may now be labelled differently and counts can move at the version boundary. Treat a new label version as a change of meaning: keep the version on every row, compare periods within one version, and map new values before the old version ends. In Fokals data a breaking change to labels ships as a new version with at least 90 days' notice.

How do I detect a silent change of meaning in a vendor feed?

A schema check cannot see one, so watch the values. Compare each column's share of empty values, the spread of each coded field and the row count with earlier loads, and alert when one moves outside its usual range. Then read the vendor's changelog for that date. A change announced under a new version name is easy to separate; the contract should rule out the unannounced kind.

What is backward compatibility in a schema registry?

It is a rule the registry applies before it accepts a new schema version. In AWS Glue Schema Registry, BACKWARD means consumers can read both the current and the previous version: deleting a field or adding an optional one passes, and adding a required field is refused. The modes ending in ALL check against every earlier version, not only the last.

The queries and code on this page are examples to adapt. Test them in your own environment before you rely on them.

What this page says about the products it names was checked against their public documentation on 7 October 2026. Product and company names are trademarks of their owners. Fokals is not affiliated with them or endorsed by them.