---
title: OpenAPI specification
description: Machine-readable OpenAPI 3.1 document for the Edgaze v1 REST API, generated from the same Zod schemas the handlers use.
source: https://www.edgaze.ai/docs/api/openapi
section: api
---
# OpenAPI specification

> Machine-readable OpenAPI 3.1 document for the Edgaze v1 REST API, generated from the same Zod schemas the handlers use.

The v1 REST API ships with a committed OpenAPI 3.1 document. Generators, docs UIs, and validators can consume it without keys, without CORS gymnastics, and without hand-maintained shim schemas.

**Audience: Developers generating SDKs, importing into Postman/Insomnia, or building custom API tooling.**

## Where to find it

- `https://api.edgaze.ai/v1/openapi` (production, dedicated host)
- `https://www.edgaze.ai/api/v1/openapi` (App Router route handler)
- `https://www.edgaze.ai/openapi.json` (committed static asset, same bytes)

All three URLs are unauthenticated, respond with `Content-Type: application/json`, allow `Access-Control-Allow-Origin: *`, and are cached publicly for one hour. Fetch the URL closest to your consumer.

## What is in the document

- `openapi: "3.1.0"` and `info.version: "1.0.0"`. The spec version is a dedicated constant, decoupled from the platform release version so unrelated deploys never move it.
- `servers` points at `https://api.edgaze.ai/v1`.
- `securitySchemes.bearerAuth` is HTTP bearer. Every non-webhook operation declares `security: [{ bearerAuth: [] }]` and carries `x-required-scopes` for programmatic scope checks.
- Eight explicit `operationId`s: `listWorkflows`, `getWorkflow`, `listWorkflowVersions`, `acceptWorkflowUpdate`, `createRun`, `getRun`, `listRunEvents`, `streamRun`. These match the handler paths under `src/app/api/v1/` and are stable across releases.
- Response headers include `Cache-Control` and `Vary` on every authenticated response. `createRun` adds rate-limit headers on 429. `streamRun` declares the SSE headers.
- `createRun` documents the `Idempotency-Key` header (max 255 chars) and the 409 `idempotency_conflict` conflict response.
- `streamRun` documents the `Last-Event-ID` resume header.
- A `webhooks` section describes `run.completed`, `run.failed`, `run.cancelled`, and `webhook.test`, each with the `edgaze-signature` HMAC verification contract.

## Zod is the source of truth

Every schema in `components.schemas` is generated from a Zod schema in `src/lib/api/v1/schemas.ts`. To evolve the API surface:

1. Edit the Zod schema.
2. Run `npm run openapi:generate`.
3. Commit the updated `public/openapi.json`.

CI runs the same generator and fails the build when the committed document drifts from the code, so you can never merge a spec that misrepresents the handlers.

## Version resolution

The public v1 API pins every run to an immutable workflow version, but the same workflow id can execute different graphs depending on who is calling. Two callers hitting POST /runs with the same `workflow` can execute two completely different immutable graphs.

POST /runs resolves the version in this order:

1. **Explicit `version` in the request body.** The run executes that exact immutable graph. The caller must be entitled to it: owners can select any version in the workflow's history; buyers can select the version their purchase pin already covers. Sending an unknown or forbidden `version` returns 403 `forbidden`.
2. **Caller's purchase pin.** When `version` is omitted and `workflow_purchases.workflow_version_id` is non-null for this caller, the run executes that pinned version. A creator publishing a newer version does not silently upgrade a pinned buyer.
3. **Follow active.** When `version` is omitted and the caller's purchase pin is null, or they have no purchase row, the run executes the workflow's current `active_version_id`. These callers float with each publish.

GET /workflows/{id} surfaces three related fields so integrators can detect and reason about drift without polling every run:

- `pinnedVersionId`: the version this caller is pinned to via a prior purchase, or `null` when they follow the active version.
- `activeVersionId`: the workflow's current active version.
- `updateAvailable`: `true` when the caller is pinned to an older version than the active one.

Cache these values per workflow. When `updateAvailable` flips to `true`, treat it as a signal to inspect any newly required inputs or output shapes before the next run. Buyers who want to re-pin to the newest version can call POST /workflows/{id}/accept-update (requires `workflow:write`).

Note: existing purchase rows with a null pin remain grandfathered as "follows active" forever. Only new purchases mint or resolve a version at purchase time.

## Undocumented endpoints

Two endpoints intentionally do not appear in the OpenAPI document:

- `DELETE /runs/{id}` exists only to return `405 method_not_allowed` with a stable envelope. Runs are immutable in the public API; documenting the DELETE would suggest deletion is supported.
- `GET /openapi` (and its aliases) is the document itself. Listing it inside itself is circular and adds no client value.

Both are recorded in `UNDOCUMENTED_V1_OPERATIONS` in `src/lib/api/v1/openapi.ts` so the completeness test in `src/lib/api/v1/openapi.test.ts` treats them as expected omissions rather than gaps.
