API Versioning Policy

Purpose

This policy defines how Hubbl evolves its customer-facing APIs over time so that:

  • Customers can build integrations against Hubbl's APIs with confidence
  • Hubbl can release improvements without breaking existing integrations
  • When a breaking change is unavoidable, customers receive predictable, sufficient notice to migrate

Scope

This policy applies to Hubbl's customer-facing API surfaces:

  • Public REST API (api.hubbl.com)
  • MCP server

The REST API and MCP server share the same policy rules but maintain independent version numbers. For example, the REST API may be on v1 while MCP is on v2.

Versioning Scheme

Hubbl uses path-based major versioning. Every customer-facing API request includes the version as a leading path segment:

  • REST: api.hubbl.com/v1/orgs/{orgId}
  • MCP: each major version is served at its own connection endpoint (mcp.hubbl.com/v1/mcp for v1; future major versions at /v2/mcp, etc.). Tool and resource URIs within a major version do not carry version segments — they're addressed by their MCP-protocol names (e.g., hubbl://issue-categories, tool get_org_info).

There is no minor or patch version in the URL. Within a major version, all additive (non-breaking) changes ship in place.

Hubbl explicitly does not use:

  • Header-based versioning (e.g., Accept: application/vnd.hubbl.v1+json)
  • Date-based versioning (e.g., /2026-05-26/...)
  • Subdomain versioning (e.g., v1.api.hubbl.com)
  • Unversioned alias paths (e.g., /stable, /beta)

Preferring Additive Evolution

Major version bumps are expensive — for Hubbl to maintain two concurrent versions, and for customers to migrate. When a breaking change is on the table, the first option to consider is shipping the new behavior as a new additive endpoint or parameter rather than modifying the existing one. For example, if /v1/orgs/{orgId}/issues needs a different response shape, prefer adding a new endpoint that returns the new shape over breaking the original.

This approach does not apply to cross-cutting changes — auth model, error envelope, pagination conventions, or anything else that can't reasonably be carried by a single new endpoint. Those remain the legitimate cases for a major version bump.

Most mature public APIs remain on v2 or v3 throughout their lifetime; Hubbl expects to follow the same pattern. Major version bumps are reserved as a last resort, used only when no additive path exists.

Change Classification

Every change to the API is classified as additive or breaking.

Additive (non-breaking)

These ship in place on the current major version without a deprecation window:

  • New endpoints
  • New optional request parameters
  • New response fields
  • New enum values, but only when the enum is explicitly documented as extensible. Enums are non-extensible by default — adding a value to a non-extensible enum is breaking.
  • New HTTP headers in responses

Breaking

These require a new major version and trigger the deprecation process for the prior version:

  • Removed endpoints, parameters, response fields, or enum values
  • Renamed fields
  • Changed data types (e.g., numberstring)
  • Changed request or response shapes, including the structure of error responses
  • Required parameters added to existing endpoints
  • Behavioral changes (e.g., default-value changes, validation-rule changes)
  • Authentication or authorization requirement changes

Edge cases

  • Bug fixes: if documented behavior changes to match documentation, this is non-breaking. If undocumented behavior that customers may rely on changes, Hubbl will document the change in the changelog and treat it as breaking when the impact is material. For example, a fix that changes the order of items in an unsorted list is not material; a fix that changes the value of a field from null to 0 for existing records is material.
  • Performance changes: non-breaking unless they materially change response times in ways that affect client timeouts.
  • Security fixes: changes that tighten authentication or authorization to address a security issue may ship without a deprecation window. These will be documented in the changelog and, where possible, communicated to affected customers ahead of the change.

When classification is uncertain, Hubbl errs on the side of treating a change as breaking and bumps the major version.

Deprecation Process

Breaking changes require a minimum 3-month deprecation window before the old major version is sunset. The 3-month minimum reflects the API's current early-customer status. Longer windows (6–12 months for breaking changes is the industry norm) will apply as the customer base grows. Additive changes do not have a deprecation window — they ship in place on the current version.

Signals

When a major version enters deprecation, customers are notified through:

  1. Changelog entry at docs.hubbl.com/changelog tagged deprecated
  2. Email notification to API key owners
  3. Surface-specific runtime signals:
    • REST: HTTP response headers on every request to the deprecated version — Deprecation: true (per RFC 9745) and Sunset: <RFC 7231 HTTP date> (per RFC 8594) — the planned sunset date.
    • MCP: the server_info tool's response annotates the deprecated version with its status and planned sunsetDate, and tool descriptions for renamed or removed tools include a deprecation notice (see MCP-Specific Rules). HTTP-layer headers are not used — MCP clients do not consume them, and the protocol-level mechanisms are the canonical channel.

Sunset

On the sunset date, the deprecated major version is removed. Requests to it return 410 Gone.

Concurrent Support

Hubbl supports the current major version and the one immediately prior simultaneously. At any point in time there are at most two supported major versions.

When a new major version is released, the previous current version enters deprecation, and the version that was already deprecated reaches sunset. For example, if v1 is current and v2 ships:

  • v2 becomes current
  • v1 enters deprecation and is supported for the deprecation window
  • Any older version (e.g., v0, if it had still been alive in deprecation) reaches sunset

Version Identification

Response header (REST)

Every REST response includes:

X-Hubbl-API-Version: 1

The value is the major version number that handled the request.

MCP responses do not carry an equivalent HTTP header. The version is identifiable from the URL path the client connects to (e.g., mcp.hubbl.com/v1/mcp) and from the server_info tool.

Discovery endpoint

GET / is the one unversioned REST endpoint — it sits above the version paths so clients can discover what versions exist before choosing one. It returns the list of available versions and their status:

{
  "versions": [{ "name": "v1", "status": "current" }]
}

Possible status values: current, deprecated.

When a deprecated version exists alongside the current one, the response includes the planned sunset date:

{
  "versions": [
    { "name": "v1", "status": "deprecated", "sunsetDate": "2026-12-01" },
    { "name": "v2", "status": "current" }
  ]
}

MCP discovery

Version discovery. MCP clients identify the major API version (v1, v2, ...) from the connection endpoint URL path they were configured against. The MCP protocol's initialization handshake also exchanges a serverInfo.version field, but that reflects Hubbl's server software version (e.g., 0.1.0) — not the API contract version covered by this policy. Programmatic access to the current API version and its deprecation status is via the server_info tool described below.

Deprecation status. MCP exposes the same version-and-deprecation info via two channels, depending on how you're reaching the server:

  • server_info MCP tool — callable from any MCP session.
  • GET / on mcp.hubbl.com — for operators and monitoring tools that want to check version state over plain HTTP without running an MCP handshake.

Both return the same { versions: [...] } shape, listing every supported MCP version (current and deprecated), each annotated with its status and — when deprecated — the planned sunset date:

{
  "versions": [{ "name": "v1", "status": "current" }]
}

When a deprecated version coexists with the current one, the response includes the planned sunset date so clients can plan their migration:

{
  "versions": [
    { "name": "v1", "status": "deprecated", "sunsetDate": "2026-12-01" },
    { "name": "v2", "status": "current" }
  ]
}

Per-tool deprecation notices (for renamed or removed tools) continue to be carried in each tool's description, as covered above.

MCP-Specific Rules

MCP follows all the rules above, with two additional guardrails specific to AI tool usage.

Tool descriptions are versioned

Tool description text is part of the tool's contract — model behavior can shift meaningfully based on description wording. Description changes follow the same classification:

  • Additive: clarifying wording, adding examples, expanding context. Ships in place.
  • Breaking: changing the documented purpose, scope, or expected use of a tool. Requires a major version bump.

Because LLM behavior is sensitive to wording, even additive description changes can shift how models call a tool. All description updates are recorded in the changelog regardless of classification so customers can correlate behavioral changes to specific revisions.

Tool renames keep aliases

When a tool is renamed, the old name remains registered as an alias for the full deprecation window. Both names route to the same handler, and the old name's description includes a deprecation note pointing to the new name.

Enforcement

All proposed API changes are reviewed against this policy. Automated checks in Hubbl's CI pipeline detect breaking changes that are not accompanied by a major version bump and block them from merging.

Appendix: Examples

Example 1 — Adding an optional filter parameter

A new optional filter query parameter is added to GET /v1/orgs/{orgId}/issues.

Classification: Additive. Existing clients that don't pass the parameter see no change. Action: Ships on the current major version. No deprecation needed.

Example 2 — Renaming a response field

The response field hubblScore is renamed to score.

Classification: Breaking. Clients reading hubblScore would break. Action: Requires a new major version. The new field name ships in /v2/; /v1/ continues to return hubblScore until sunset.

Example 3 — Adding a new endpoint

A new endpoint GET /v1/orgs/{orgId}/users is added.

Classification: Additive. No existing client is affected. Action: Ships on the current major version.

Example 4 — Renaming an MCP tool

The tool get_org_info is renamed to lookup_org.

Classification: Breaking. AI clients calling get_org_info by name would fail. Action: lookup_org is added as the new name. get_org_info remains registered as an alias routing to the same handler for the full deprecation window. The old tool's description includes a deprecation note pointing to the new name.

Example 5 — Rewriting an MCP tool description

The description for get_org_issues is rewritten to emphasize the fields parameter for token efficiency.

Classification: Additive if it clarifies existing behavior; breaking if it changes the documented purpose of the tool. Action: If additive, ships on the current major version. If breaking, requires a major version bump.