Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt

Use this file to discover all available pages before exploring further.

Spec: PF-89 — API Versioning & Edge Function Lifecycle
Last Updated: 2026-03-25

Overview

Edge Functions support application-level API versioning via the X-API-Version header. Callers request a specific version (e.g. v1, v2); the withVersioning middleware routes to the correct handler. If no header is sent, the latest stable version (highest major key) is used. Versioning is opt-in per function and gated by ENABLE_API_VERSIONING.

Quick Start — Adding Versioning to a Function

1. Define a contract

Create supabase/functions/_shared/contracts/my-function.contract.ts:
/** V1 request */
export interface MyFunctionV1Request {
  organization_id: string;
  name: string;
}

/** V1 response */
export interface MyFunctionV1Response {
  success: boolean;
  id: string;
}
Re-export from _shared/contracts/index.ts.

2. Wrap with withVersioning

import { withVersioning } from '../_shared/versioning.ts';

async function v1Handler(req: Request): Promise<Response> {
  // existing logic
}

Deno.serve(withVersioning('my-function', { v1: v1Handler }));

3. (Optional) Add a v2

async function v2Handler(req: Request): Promise<Response> {
  // new logic
}

Deno.serve(
  withVersioning('my-function', { v1: v1Handler, v2: v2Handler }, {
    deprecated: {
      v1: { sunset: '2026-09-01', successor: 'v2' },
    },
  }),
);

How It Works

  1. Caller sends X-API-Version: v1 header.
  2. withVersioning looks up handlers['v1'].
  3. If found → executes handler; if deprecated → merges Deprecation / Sunset / Link headers.
  4. If not found → returns 400 with migration guidance (PF-07 error envelope).
  5. If no header → defaults to highest version key.

Feature Flag

Set ENABLE_API_VERSIONING=true in Supabase Edge Function secrets. When unset/false, all requests pass through to the default (latest) handler with no version negotiation.

Contract Conventions

  • File: _shared/contracts/{function-name}.contract.ts
  • Naming: {FunctionName}V{N}Request, {FunctionName}V{N}Response
  • Major-only semver surface: v1, v2 — minor/patch changes stay backward-compatible
  • Re-export all contracts from _shared/contracts/index.ts

Deprecation Headers

When a version is marked deprecated, responses include:
HeaderExample
Deprecation@1711929600 (Unix timestamp)
SunsetSat, 01 Sep 2026 00:00:00 GMT
Link</functions/v1/my-function>; rel="successor-version"
Callers should monitor for Deprecation headers and plan migration before Sunset.

CI Contract Validation

Run npx tsx scripts/edge-contracts/diff-contracts.ts to detect breaking changes (removed exports) in contract files. This runs automatically on PRs touching *.contract.ts.
  • Additions (new exports): non-breaking ✅
  • Removals (deleted exports): breaking ❌ — bump major version

Consumer Obligations

  1. Send X-API-Version header or accept the default (latest stable).
  2. Handle 400 responses with migration guidance when a version is unsupported.
  3. Respect Sunset dates by migrating before the removal deadline.
  4. Monitor Deprecation headers in responses.