The API versioning decision record: why the versioning scheme you chose determines your client migration surface and your breaking change detection gap

The API versioning scheme, breaking change classification policy, and version sunset rules are decisions that are almost never made explicitly — they emerge from a framework convention, a copied URL pattern from a popular API docs page, and an implicit assumption that clients will migrate when asked. Three failure patterns: the team whose URL-path versioning gave them zero visibility into which clients were still on v1 until after the endpoints were removed and two enterprise ETL pipelines went silent; the team whose deprecated field removal produced data corruption in three enterprise integrations because their deprecation announcement reached community followers, not active API callers; and the team entering year five maintaining three simultaneous API versions with no sunset date in sight because no sunset policy was ever written down.

A 34-person B2B SaaS company built a workflow automation platform for operations teams at mid-market logistics and supply chain companies. The platform exposed a REST API that customers used to integrate their warehouse management systems, ERP platforms, and custom internal tooling with the workflow engine. When the engineering team shipped a major redesign of the resource schema — a restructuring of the event payload format that improved consistency across resource types but was not backwards-compatible with the existing response shape — they adopted URL-path versioning: the existing API became /v1/ and the new API launched as /v2/. The choice was made in an afternoon by two engineers reviewing the API docs for Stripe and GitHub, who both used URL-path versioning, and it was recorded as an implementation detail rather than as a decision with downstream consequences for how client migrations would be managed.

The engineering team announced the v2 launch in a changelog blog post and a pinned message in their developer community Slack. They announced a six-month deprecation window for v1, with the end-of-life date set six months from the v2 launch. They sent a single email to all customers with active API keys. Over the following five months, the team watched their API analytics show v2 traffic growing and v1 traffic declining — from 100% of requests at launch, to roughly 30% at four months, to approximately 12% at month five. The analytics showed total v1 request volume declining, which the team interpreted as evidence that migration was nearly complete. Two weeks before the end-of-life date, they sent a final reminder email to all API key holders and posted in the Slack community. On the end-of-life date, they removed the v1 routing and returned 410 Gone from all /v1/ paths.

Within forty minutes of the cutover, two enterprise customers filed support tickets. Both were large accounts — a 280-person third-party logistics provider and a 340-person distribution company — and both were reporting that their nightly data pipeline jobs had failed. Investigation revealed that both companies had ETL pipelines, built by contractors eighteen months earlier, that called the v1 API to extract workflow event history for nightly loading into their internal data warehouses. The contractors had long since left both companies. The current engineering teams at both customers were not aware that the API calls were happening — the integration had been built, tested, and then left running as infrastructure. Neither customer's current engineering team had seen the deprecation emails, because the emails had been sent to the account owner address on the API key — in both cases, a former employee — rather than to any current technical contact. The Slack community had been checked by neither company's current team, as neither had a developer who actively followed the vendor's community channel.

The fifteen percent of v1 traffic still running at month five had not been fifteen percent of customers who knew about the deprecation and hadn't gotten around to migrating — it had included two large customers whose entire integration teams had turned over since the integration was built. The analytics the engineering team had been watching showed declining v1 request volume, which was accurate, but did not show whether the remaining v1 callers were aware of the migration timeline or capable of completing the migration in the remaining window. URL-path versioning made it easy to see that v1 traffic existed; it provided no mechanism to understand who was calling v1 or whether those callers had received and processed the migration notice. The decision to use URL-path versioning had been made on the basis of URL aesthetics and industry convention, not on the basis of what information the versioning scheme would need to provide to manage the deprecation of v1 safely.

A 27-person SaaS company built a customer communications platform for direct-to-consumer e-commerce brands — a tool that managed email and SMS campaign scheduling, list segmentation, A/B test orchestration, and deliverability analytics. The platform's API was used by brand customers to integrate their Shopify stores, custom order management systems, and customer data platforms with the campaign engine. During a cleanup sprint eighteen months after the API's initial release, the engineering team reviewed the response schema and identified a field — legacy_segment_id — that had been included in the original response design as a bridge compatibility field for customers migrating from a previous internal segmentation engine. The field contained the ID from the old segmentation system, parallel to the primary segment_id field that used the new segmentation engine's IDs. The old segmentation engine had been fully decommissioned twelve months earlier.

The team's API analytics showed that legacy_segment_id was always an empty string in current responses — the old segmentation engine it referenced no longer existed, so the field was populated with an empty string as a safe fallback. The team concluded the field was unused: every response contained it as an empty string, no one had asked about it in support tickets, and the migration from the old segmentation engine had completed the previous year. They marked it deprecated in the documentation and announced its removal in a changelog blog post titled "API cleanup: removing legacy compatibility fields in v2.1" and in a developer community Slack message. The removal shipped three weeks later.

Two weeks after the removal, a third enterprise customer — a 180-person outdoor apparel brand — opened a support ticket reporting that their email campaign performance reports for the previous two weeks had shown anomalous segment attribution: campaigns were reporting zero segment overlap metrics that had previously shown meaningful cross-segment behavior. The investigation traced the anomaly to the customer's analytics backend, which consumed the campaign API and derived segment overlap metrics from a combination of segment_id and a cached mapping of legacy_segment_id values that their data team had built as an internal cross-reference during the segmentation engine migration the previous year. When legacy_segment_id returned an empty string before the removal, the mapping lookup silently failed — a null-safe code path treated the empty string as a missing key and skipped the cross-reference. After the field was removed entirely and the response no longer contained the key, a different code path triggered that set the metric to zero. No error was raised in either state — the behavior change was entirely in computed output values that were only visible in downstream analytical reports.

Two other enterprise customers had similar patterns: code paths that handled the empty string value in one way and the absent key in a different way, producing output changes visible only in analytical outputs rather than in application errors or API error logs. The deprecation announcement had reached approximately 400 people who followed the changelog or the Slack community — none of the three affected integrations were maintained by people who monitored either channel. The team had no mechanism to identify which API callers were reading legacy_segment_id from their responses, because the field appeared in every response (always as an empty string) and their analytics recorded what fields were requested, not what fields clients parsed from the response. The removal had been classified as safe — "the field is always empty, it can't be used for anything" — without an audit of whether clients were reading and handling the field in their own code.

A 46-person B2B SaaS company built a developer productivity platform — a service that managed internal documentation, architecture diagrams, and team knowledge bases for engineering organizations at mid-market technology companies. The platform's API had been available for four years. Version 1 had launched with API keys passed as query parameters (?api_key=...) because the original developer who designed the API had copied the pattern from a Mailchimp integration guide, and the team had moved quickly. When v2 launched eighteen months later, the team moved to Bearer token authentication in the Authorization header — a necessary change because the query-parameter key pattern was logging credentials in web server access logs and reverse proxy logs, a security audit had flagged it, and several large customers had raised concerns after discovering their API keys in log aggregation outputs. v2 also introduced a restructured response schema that was not backwards-compatible with v1.

v3 launched two and a half years after v2, adding OAuth 2.0 authorization code flow for enterprise customers who required SSO integration and scoped token delegation. OAuth 2.0 was a prerequisite for the enterprise tier features the sales team had been promising — the ability for individual team members to authenticate with their organization's identity provider and receive scoped access to specific documentation spaces without admin provisioning. Three enterprise deals were contingent on OAuth 2.0 availability. v3 launched alongside v2 (Bearer token) for customers who did not need enterprise features.

Four and a half years after the v1 launch, the engineering team was maintaining all three versions in production. v1 traffic accounted for 3% of total API volume — low in percentage terms but representing eight customer accounts, including one account that was the company's fourth-largest by revenue. That account's integration had been built by a development agency that had completed the engagement and was no longer reachable; the current technical contact at the customer was a non-technical operations manager who had inherited ownership of the integration. The customer's development team had a three-month backlog queue and the migration had been deprioritized eleven times across four and a half years because the integration "worked" — v1 continued to function, there was no immediate pressure to migrate, and the API-key-in-query-parameter pattern had been addressed at the customer's network level by filtering the query parameter from their log aggregation. v2 traffic accounted for 58% of API volume, v3 accounted for 39%.

The cost of maintaining three versions was not primarily the operational overhead of running three codebases — the three versions shared a monorepo and the routing layer was well-abstracted. The cost was the compatibility ceiling. v3 required OAuth 2.0 authorization semantics, which the product team wanted to use as the foundation for a new permission model allowing granular workspace-level access control. The permission model required knowing which authenticated principal was making each API call — information available in OAuth 2.0 token claims, present in Bearer token metadata for v2, and absent in v1's query-parameter key model where the key identified a service account, not an individual principal. Building the new permission model required either excluding v1 clients from the feature or implementing a compatibility shim that mapped v1 service account keys to a synthetic principal identity — a shim that would need to be maintained indefinitely as long as v1 remained in production. The product team deferred the permission model launch by one quarter while legal and security reviewed the compatibility shim approach, and the engineering team spent those three months maintaining three-version infrastructure instead of building features that would generate revenue. A sunset policy written at the time of the v1 launch — one that established a maximum end-of-life date rather than an open-ended "sunset when clients migrate" approach — would have created the coordination pressure four years earlier that would have resolved the situation in eighteen months instead of fifty-four.

Structural properties set by the API versioning decision

Three structural properties are determined when an engineering team establishes — or fails to establish — an API versioning decision record: what visibility the versioning scheme provides into the client migration surface during deprecation windows, what definition the team uses for a breaking change and what procedure verifies that active callers have updated before a deprecated capability is removed, and what conditions cause an old API version to reach end-of-life and what happens when those conditions are not met. None of these are labeled as decisions when the team picks URL-path versioning by looking at Stripe's docs — they emerge as operational constraints years later, when the first deprecation window closes and the team discovers they can't verify who is still calling the old version, or when the team enters year five supporting an API version whose authentication model blocks the features they want to build.

Property 1: The versioning scheme and the client migration surface. The client migration surface is the set of callers who are still using a deprecated API version and whose integrations will break when that version is removed. The versioning scheme determines what measurement points exist for identifying the migration surface before the cutover. URL-path versioning creates a routing dimension — every request to a deprecated version includes the version prefix in the path, and every access log entry, analytics event, and tracing span captures the version as a first-class attribute. The migration surface is queryable: a log aggregation query for /v1/ path prefixes in the trailing thirty days produces the complete set of active v1 callers. Header-based versioning requires the version header to be present and logged — callers who omit the header and receive a default version are invisible in the version distribution analytics. Content-type versioning creates the same invisibility problem for callers who omit the Accept type parameter. The versioning scheme decision is therefore a decision about how the team will manage deprecation, not just a decision about URL aesthetics. A team that has not thought through the deprecation management process at the time the versioning scheme is chosen will discover the gap when they run their first pre-removal traffic audit and find that their logging infrastructure does not capture the version dimension they need. The decisions never written down in the API versioning domain frequently include the migration surface measurement requirement — the team that copies URL-path versioning from a popular API's docs page has not necessarily internalized that the migration surface visibility it provides was a deliberate design choice, not an incidental property of the URL pattern.

Property 2: The breaking change classification and the deprecation detection gap. The deprecation detection gap is the interval between the time a breaking change is announced and the time the provider verifies that active callers have updated their integrations. Teams that close deprecation windows by calendar — removing the deprecated capability when the announced window expires — accept the detection gap as residual risk: if callers have not updated, they will break. Teams that close deprecation windows by migration verification — removing the deprecated capability only after a pre-removal traffic audit confirms zero active callers — eliminate the detection gap but may find that the window never closes if some callers never migrate. The breaking change classification policy determines which changes require a deprecation window and which can be shipped without version coordination. The most dangerous misclassification is classifying a behavioral change as non-breaking on the basis of the provider's own analytics about field usage — the cases where this fails are precisely the cases where client code consumes a field value in a non-obvious way that does not show up in the provider's instrumentation: null-coalescing, silent fallbacks, cached mappings derived from field values that the client stores locally. The observability strategy decision record connects at the migration surface measurement layer: the observability infrastructure that captures per-version, per-endpoint, and per-API-key traffic is the data source for the pre-removal traffic audit; teams that have not instrumented this dimension will discover the gap when they need to audit active v1 callers and their observability data only answers "how many total v1 requests were there this month," not "which specific API keys called which specific deprecated endpoints in the trailing thirty days." The logging strategy decision record connects at the per-request attribution layer: access logs that capture the API key, the version routing dimension, and the specific endpoint path called produce the complete audit trail for pre-removal verification; logs that capture only aggregate metrics leave the callers who matter invisible.

Property 3: The version proliferation model and the compatibility ceiling. The compatibility ceiling is the product and engineering design surface that is blocked by the obligation to maintain compatibility with older API versions. Each active API version carries a compatibility obligation — the team must maintain the authentication model, response schema, error handling behavior, and documentation for that version, and must evaluate every new feature and every cross-cutting change against whether it can be implemented without breaking the older version's contract. A new authentication model that requires principal identity information can only be adopted by callers on the version that provides that information — callers on older versions are excluded from features built on the new model. The compatibility ceiling rises with each new version added to the simultaneous support matrix and falls only when old versions are sunset. A team that has never written a version sunset policy has accepted indefinite compatibility ceiling growth as the default outcome. The CI/CD pipeline decision record connects at the multi-version regression surface: a pipeline that runs tests against the current version only will not detect when a shared-infrastructure change breaks an older version's contract; teams maintaining multiple simultaneous API versions need a test suite that covers the behavior contract for each version running against every change to shared infrastructure. The WhyChose extractor finds the API versioning decisions buried in your AI session history — the architecture review session where URL-path versioning was adopted by convention, the post-incident retrospective session where the migration surface visibility gap was first discussed, and the quarterly planning session where the v1 sunset was deferred for the eleventh time because "the customer hasn't finished their migration yet."

The API versioning ADR: five sections

Section 1: Versioning scheme selection and migration surface visibility. Specify the versioning scheme — URL-path versioning, header-based versioning, content-type versioning, or date-based versioning — and document the migration surface visibility properties that the chosen scheme provides. The migration surface visibility requirement should be stated explicitly: before removing any deprecated API version, the team must be able to identify, from the logging and analytics infrastructure available at the time of removal, every active caller of that version by API key, account, and endpoint in the trailing thirty days. Evaluate whether the chosen versioning scheme, combined with the current logging infrastructure, satisfies this requirement. URL-path versioning satisfies it if access logs capture the full request path and are queryable by path prefix. Header-based versioning satisfies it if the version header is present on all requests from all clients and is captured in access logs — teams adopting header-based versioning should add a middleware layer that logs the version header as a first-class log field and falls back to the API key's provisioned default version if the header is absent, so that callers who omit the version header are still attributed to a version in the analytics. If the current logging infrastructure does not satisfy the migration surface visibility requirement for the chosen scheme, document the instrumentation gap as a dependency that must be resolved before the first deprecation window is opened. Connect this section to the observability strategy decision record for the logging instrumentation requirements and to the logging strategy decision record for the per-request attribution fields — API key, version dimension, and endpoint path — that the migration surface audit requires.

Section 2: Breaking change classification policy and the deprecation trigger. Define what constitutes a breaking change and what triggers the deprecation process. The classification policy should enumerate the categories of change that are always breaking (field removal, type changes, semantic meaning changes, authentication model changes, required field additions, endpoint removals), the categories that require evaluation (response shape restructuring, rate limit reductions, enum value changes), and the categories that are always non-breaking (optional field additions, new endpoints, performance improvements, optional authentication method additions). Establish the evaluation procedure for gray-area changes: a breaking change candidate that does not fall clearly into the always-breaking or always-non-breaking categories should be evaluated by running a pre-change traffic audit against the trailing thirty days of access logs to identify callers that would be affected, and the change should be classified as breaking if any active caller could be affected. The deprecation trigger is the event that begins the deprecation clock: release of a successor version that covers the same use cases, or a security or compliance requirement that makes the current version's behavior untenable. Document the deprecation trigger condition so that the team has a clear criterion for when a version enters the deprecation period rather than remaining in indefinite "maintenance mode." Connect this section to the CI/CD pipeline decision record for the automated breaking change detection step that should run in the pipeline against every schema change, comparing the current response shape against a recorded baseline for each active API version.

Section 3: Client usage instrumentation and the pre-removal traffic audit procedure. Specify the instrumentation required to run a pre-removal traffic audit and the procedure for conducting the audit before any deprecated API version, endpoint, or field is removed. The instrumentation requirement: access logs must capture the API key (or OAuth 2.0 client ID), the full request path (including version prefix for URL-path versioned APIs), and the response status code, with log retention sufficient to cover at least the full deprecation window. The audit procedure: within two weeks of the deprecation window's end date, run a query against access logs for the trailing thirty days identifying every API key that called any deprecated endpoint or version. For each active caller identified: (1) look up the account owner and current technical contact for the API key in the customer database; (2) send a direct notification to the current technical contact (not the API key's owner address, which may be a former employee) with the specific deprecated endpoints called, the volume and recency of calls, and the migration guide URL; (3) record the caller in the pre-removal audit log with their notification date and a follow-up window; (4) escalate to the account manager for any active caller that has not acknowledged the notification within one week. The pre-removal audit is not a calendar checkpoint — it is a verification step: the deprecated capability is removed only when the audit shows zero active callers in the trailing thirty days, or on the maximum end-of-life date established in the sunset policy, whichever comes first. Connect this section to the observability strategy decision record for the log retention policy and the logging strategy decision record for the per-request fields that the audit query requires.

Section 4: Deprecation communication procedure and the notification surface. Specify the communication channels and timing for deprecation announcements, with a clear distinction between community-awareness channels (changelog, developer blog, community Slack) and active-caller notification channels (targeted email to current technical contacts of active callers, deprecation response headers on deprecated endpoints). Community-awareness channels should be used for all deprecation announcements — they reach the developers who are evaluating the API, building new integrations, and following the vendor's developer community. Active-caller notification channels must be used in addition, because the integrations that will break are frequently maintained by people who are not following community channels. The deprecation response header procedure: beginning on the deprecation announcement date, every response from a deprecated endpoint should include a Deprecation header with the ISO 8601 sunset date value and a Link header with a reference to the migration guide. These headers appear in every response, in every HTTP client log, and in every tracing span — they are the notification channel that reaches the integration itself rather than the humans who may or may not be watching community channels. The notification timing: deprecation announcement on day 0 (community channels plus targeted email to all API keys that called the deprecated capability in the trailing 90 days), deprecation headers on all deprecated responses beginning day 0, mid-window reminder at 50% of the deprecation window elapsed (targeted email to active callers still calling deprecated capabilities per access log query), pre-removal audit and direct outreach at two weeks before end-of-life. Connect this section to the incident response playbook decision record for the procedure when a deprecated endpoint removal causes unexpected client failures that require rollback — the rollback decision and the communication to affected customers should be defined in advance, not improvised under incident pressure.

Section 5: Version sunset policy and the compatibility ceiling contract. Specify the conditions under which each API version reaches end-of-life, including a maximum end-of-life date that is independent of whether all callers have migrated. The sunset policy should specify: the minimum deprecation window (the time between the formal deprecation announcement and the earliest possible removal date, typically six to twelve months depending on the API's enterprise customer concentration and procurement cycle length), the maximum end-of-life date (the date after which the version will be removed regardless of remaining callers, typically two to three years from the version's initial release, or twelve to eighteen months after the successor version reaches general availability), the compatibility exception process (the procedure for a specific customer to request an extended migration window beyond the standard maximum end-of-life date — typically limited to one extension per customer, for a maximum of six months, with the customer assuming the engineering cost of maintaining the compatibility shim for their account), and the compatibility ceiling audit cadence (a quarterly review of the features and design decisions blocked by the compatibility obligation of each active older version, documented so that the product team can make explicit decisions about whether the blocked features justify the cost of accelerating the sunset). The maximum end-of-life date is the mechanism that prevents the compatibility ceiling from rising indefinitely — it creates a hard coordination event for callers who have not migrated, converts the open-ended support obligation into a bounded one, and gives the engineering and product teams a planning horizon for when the compatibility ceiling will lower. Connect this section to the CI/CD pipeline decision record for the multi-version test suite that must run until each version reaches its end-of-life date, and to the decisions never written down series for the broader pattern of why version sunset policies — like availability commitment tiers and maintenance exclusion policies — are almost always set implicitly rather than explicitly, and why the cost of the implicit setting only becomes visible years later when the compatibility ceiling is blocking the product roadmap.

FAQ

What is the difference between URL-path versioning, header-based versioning, and content-type versioning, and which should I choose?

URL-path versioning embeds the version in the URL (/v1/resources, /v2/resources). It is the most visible scheme — clients cannot accidentally call a version they did not intend to call, caching and logging infrastructure handles versions as distinct resources, and analytics systems can report per-version traffic without special instrumentation. The cost is that version proliferation is visible in URLs permanently, which some teams find aesthetically objectionable. Header-based versioning uses a custom request header (Accept-Version: 2, or API-Version: 2026-09-01) to route requests to the appropriate version. It keeps URLs stable, but clients who omit the header receive a default version, and the migration surface is only visible if the header is reliably present and logged. Content-type versioning uses Accept and Content-Type media type parameters (application/vnd.company.v2+json) to negotiate versions per-request — the most REST-principled scheme but the hardest to implement correctly and debug. For most teams building B2B APIs with enterprise integrations, URL-path versioning is the lowest-risk choice: it makes the version explicit in every request, every log entry, and every analytics query; it creates unambiguous routing without header-parsing logic; and it makes the migration surface directly queryable from access logs without additional instrumentation. The aesthetic cost of version-prefixed URLs is lower than the operational cost of invisible version distribution during deprecation windows.

What counts as a breaking change, and how should teams classify API changes before shipping them?

A breaking change is any modification that causes a correctly-written client — a client that follows the API documentation and handles the documented response shapes — to produce a different result, raise an error, or require code changes to continue operating correctly. Breaking changes include: removing a field from a response object; changing the type of a field (string to integer, object to array); changing the semantic meaning of a field value without changing its type; adding a new required request field; removing an endpoint or operation; changing an authentication mechanism; and changing error codes or error response shapes in ways that break client error handling. Non-breaking changes include: adding new optional response fields; adding new optional request fields with safe defaults; adding new endpoints; and improving performance without changing semantics. The most dangerous misclassification is removing a response field that appears unused based on the provider's own analytics. Response field consumption happens in client code — null-coalescing patterns, silent fallbacks, and cached mappings derived from field values produce behavior changes when a field is removed that are invisible in application error rates and only visible in analytical outputs, sometimes weeks later. The pre-removal traffic audit procedure, not the provider's intuition about usage, is the correct mechanism for establishing that a change is safe to ship without version coordination.

How should teams communicate API deprecations so that active callers receive the notification rather than community followers?

Deprecation communication fails when it reaches the wrong audience. Community Slack channels, developer blog posts, changelog pages, and mailing list announcements reach people who are interested in the API — but active callers whose integrations will break are not always the same people. Enterprise integrations are frequently built by contractors who have left the company, or by backend services maintained by teams whose engineers do not follow the vendor's developer community. The correct notification surface for breaking change announcements is the integration itself, not the community around it. The most reliable channels for reaching active callers are: (1) Deprecation response headers on every response from a deprecated endpoint — the Deprecation header with the sunset date and a Link header pointing to the migration guide appear in HTTP client logs, proxy logs, and tracing spans regardless of whether the humans maintaining the integration follow community channels; (2) Email notification to the current technical contact on file for every API key that has called the deprecated endpoint in the trailing thirty days — this targets active callers specifically, not the entire customer base. The pre-removal audit at two weeks before the end-of-life date identifies remaining active callers, and those callers should receive direct outreach — account manager contact, not only automated email — before the endpoint is removed.

What should a version sunset policy specify, and how does it prevent version proliferation?

A version sunset policy specifies the conditions under which an API version reaches its end-of-life date and what happens at that date. Without a sunset policy, API versions accumulate indefinitely — the team supports v1 "until clients migrate," some clients never fully migrate, and the team enters year three or year five maintaining authentication schemes, response schemas, and documentation for versions they would prefer to retire. A sunset policy should specify: the deprecation trigger (what event causes a version to be formally deprecated — typically the release of a successor version); the minimum deprecation window (typically six to twelve months for B2B APIs); the maximum end-of-life date (the date after which the version is removed regardless of remaining callers — typically two to three years from initial release, or twelve to eighteen months after the successor version reaches general availability); and the compatibility exception process (how a specific caller can request an extended migration window, under what conditions the exception is granted, and what additional support costs the caller assumes). The maximum end-of-life date clause is the mechanism that prevents indefinite accumulation — without a hard maximum date, "some clients never migrate" is always true for some client, and the sunset is perpetually deferred. With a hard maximum date, the sunset creates a coordination event for remaining callers, and the pre-removal audit gives those callers the final opportunity to escalate within their own organizations before the endpoint is removed.

Further reading

  • Observability strategy decision record — the logging and observability infrastructure that makes per-version, per-API-key traffic audits possible is a prerequisite for running meaningful pre-removal audits before deprecation windows close.
  • Logging strategy decision record — the per-request attribution fields — API key, version dimension, endpoint path — that the migration surface audit requires must be captured in the logging strategy, not retrofitted when the first deprecation window approaches.
  • CI/CD pipeline decision record — multi-version regression testing and automated breaking change detection are CI/CD responsibilities; the pipeline that runs only against the current version will not catch when shared-infrastructure changes break an older version's contract.
  • Incident response playbook decision record — the rollback decision and customer communication procedure for unexpected failures caused by deprecated endpoint removal should be defined in the incident response playbook before the first cutover, not improvised under incident pressure.
  • Decisions never written down — the versioning scheme adopted by convention, the breaking change classification that produces silent data corruption, and the sunset policy never established are canonical examples of decisions made without being labeled as decisions.
  • Open-source extractor — find the API versioning decisions buried in your AI chat history: the architecture review where URL-path versioning was adopted by convention, the post-incident retrospective where the migration surface visibility gap was first discussed, and the quarterly planning session where the v1 sunset was deferred for the eleventh time.