docs / reference
REST API
Get a key, call the API, connect an MCP client, and read every public route. Generated from the same route table the OpenAPI document is generated from.
complete · updated 1 september 2026
The REST API is in the free tier, rate-limited, with scoped tokens and a published OpenAPI document. Everything the dashboard does, the API does: it is the same /v1 routes the dashboard calls, authenticated with an fwz_ key instead of a session. There is no second code path.
- The rendered reference — every operation with its request and response schema.
- Error codes — what each
codein the envelope means, and what to do about it. Every non-2xx body carries adocsUrlpointing at its own anchor there. - openapi.json — the document both of the above are built from.
Get a key
- Sign in and open Settings → API keys. Minting a key needs the owner or admin role.
- Create key, give it a name, and tick the narrowest scopes that do the job:
freeze:readfor a deploy gate,freeze:writeto freeze and thaw. Scopes are fixed at creation and can never be widened. - Pick an expiry. A key declared as an agent key must expire within 90 days.
- Copy the secret. It is shown once. Then
export FWOZEN_TOKEN=fwz_live_…and send it asAuthorization: Bearer $FWOZEN_TOKEN.
A key is organisation-wide and never user-scoped, so the scope list is the authorization. Two routes it can never call are minting another key and setting enforcement up: both are session-only and answer 403 credential_type_not_allowed, never a 401, so a script can tell the two apart. Rotating a key issues a new secret and keeps the old one working for a grace window, which is what makes a rotation something you can roll through CI without a deploy.
Calling it
curl -s "https://api.fwozen.com/v1/freeze-state?repo=acme/api-server" \
-H "Authorization: Bearer $FWOZEN_TOKEN"- JSON in, JSON out. Send
Content-Type: application/jsonon anything with a body.curl -ddeclares a form body on its own and the API answers400 unsupported_content_type. - Idempotency.
Idempotency-Keyon a write makes a retry safe. The same key with a different body is a409, so use one key per intent. - Pagination. Cursor-based. Follow the cursor the response gives you rather than building one.
- Rate limits. Read
RateLimit-RemainingandRateLimit-Resetoff every credentialled response and honourRetry-Afteron a 429. No ceiling is published here, because the numbers are operational settings and a figure in prose would be a promise nobody made. - Unknown fields.
/v1is additive-only: new response fields ship without notice, so ignore the ones you do not know and treat an unfamiliar enum value as opaque.
Connect an MCP client
The same routes are a streamable-HTTP MCP server at https://api.fwozen.com/mcp. It takes the same two credentials the REST API does, and there is no MCP-specific token to go looking for. The header path is the one that works everywhere:
claude mcp add --transport http fwozen https://api.fwozen.com/mcp \
--header "Authorization: Bearer $FWOZEN_TOKEN"Clients that read a config file take the same two lines:
{
"mcpServers": {
"fwozen": {
"type": "http",
"url": "https://api.fwozen.com/mcp",
"headers": { "Authorization": "Bearer fwz_live_…" }
}
}
}There is an OAuth path too, for clients that support client id metadata documents: point the client at the same URL with no header and it will be sent to the consent page. Dynamic client registration is deliberately not offered, so a client that can only do DCR has to use the header instead. A request with no credential answers 401 with a WWW-Authenticate header naming /.well-known/oauth-protected-resource, which is the discovery chain an MCP client follows on its own.
The tools are thin adapters over the routes below and carry the same authorization: a key that cannot call a route cannot call its tool. Reads and writes are never mixed in one tool, fwozen_enable_repos takes an explicit repository list, and fwozen_end_freeze is marked destructive and refuses without confirm: true.
Every public route
Generated from the same route table the OpenAPI document and llms-full.txt are generated from. auth says which credential a route takes: key is an fwz_ API key, session is a signed-in session or a device-flow token, both is either, and none takes no credential at all. Where scopes are listed, a key needs any one of them.
Organizations
GET /v1/me— Current user and organization auth: sessionGET /v1/me/organizations— Organizations the current user belongs to auth: sessionGET /v1/onboarding— Onboarding state auth: sessionPOST /v1/onboarding/bootstrap— Create the organization for the signed-in user (idempotent) auth: sessionGET /v1/github/install-url— GitHub App installation URL carrying a signed state nonce auth: sessionGET /v1/installations/status— Poll a GitHub App installation minted by GET /v1/github/install-url auth: both · scopes: repo:readPOST /v1/installations/claim— Claim a GitHub App installation for this organization auth: sessionGET /v1/orgs/current— Get the organization auth: both · scopes: repo:readPATCH /v1/orgs/current— Update organization settings auth: sessionGET /v1/members— List members auth: sessionPATCH /v1/members/{userId}— Change a member's role auth: sessionDELETE /v1/members/{userId}— Remove a member auth: sessionGET /v1/invitations— List invitations auth: sessionPOST /v1/invitations— Invite a member auth: sessionDELETE /v1/invitations/{invitationId}— Revoke an invitation auth: sessionGET /v1/invitations/pending— Invitations addressed to you auth: sessionGET /v1/invitations/preview— Read an invitation from its token auth: sessionPOST /v1/invitations/{invitationId}/accept— Accept an invitation auth: sessionGET /v1/invitations/{invitationId}/link— Mint the accept link for a pending invitation auth: sessionGET /v1/overview— Dashboard rollup auth: both · scopes: freeze:readGET /v1/attention— Things needing attention auth: both · scopes: freeze:read
Repositories
GET /v1/repos— List repositories auth: both · scopes: repo:readPOST /v1/repos/sync— Re-sync the repository mirror from GitHub auth: both · scopes: repo:writePOST /v1/repos/enable— Enable repositories auth: both · scopes: repo:writePOST /v1/repos/disable— Disable repositories auth: both · scopes: repo:writePOST /v1/repos/preview-glob— Preview which repositories a glob matches auth: both · scopes: repo:readGET /v1/repos/{repoId}— Get a repository auth: both · scopes: repo:readPATCH /v1/repos/{repoId}— Update repository settings auth: both · scopes: repo:writeGET /v1/repos/{repoId}/pulls— List tracked pull requests of a repository auth: both · scopes: freeze:readGET /v1/pulls/lookup— Resolve a PR from a URL, owner/repo#123, or a number auth: both · scopes: freeze:read
Branches
GET /v1/repos/{repoId}/branches— List watched branches of a repository auth: both · scopes: repo:readGET /v1/repos/{repoId}/remote-branches— List branches live from GitHub (cached 60s, budget-gated) auth: both · scopes: repo:readPOST /v1/repos/{repoId}/branches— Watch a branch auth: both · scopes: repo:writeGET /v1/branches— List watched branches auth: both · scopes: repo:readGET /v1/branches/{branchId}— Get a watched branch auth: both · scopes: repo:readPATCH /v1/branches/{branchId}— Update watched-branch settings auth: both · scopes: repo:writeDELETE /v1/branches/{branchId}— Stop watching a branch auth: both · scopes: repo:write
Enforcement
GET /v1/enforcement— Enforcement traffic light across the organization auth: both · scopes: repo:readGET /v1/enforcement/branches/{branchId}— Enforcement detail for a branch auth: both · scopes: repo:readGET /v1/enforcement/branches/{branchId}/snippets— gh CLI, Terraform and ruleset JSON snippets for a branch auth: both · scopes: repo:readPOST /v1/enforcement/verify— Queue an enforcement probe auth: both · scopes: repo:writePOST /v1/enforcement/setup— Plan the native GitHub rule, or have Fwozen apply it auth: sessionPOST /v1/enforcement/seed-check— Write the current fwozen verdict to every enforcement-relevant head auth: session
Freezes
POST /v1/scope/preview— Resolve a freeze scope without creating a freeze auth: both · scopes: freeze:readPOST /v1/freezes— Start a freeze auth: both · scopes: freeze:writeGET /v1/freezes— List freezes auth: both · scopes: freeze:readPOST /v1/freezes/lift— Lift every freeze matching a scope auth: both · scopes: freeze:writeGET /v1/freezes/{freezeId}— Get a freeze auth: both · scopes: freeze:readGET /v1/freezes/{freezeId}/targets— List the materialized targets of a freeze auth: both · scopes: freeze:readPOST /v1/freezes/{freezeId}/lift— Lift a freeze auth: both · scopes: freeze:writePOST /v1/freezes/{freezeId}/extend— Extend a freeze auth: both · scopes: freeze:writePOST /v1/freezes/{freezeId}/thaw-override— Unfreeze inside a scheduled window, suppressing only that freeze auth: both · scopes: freeze:writePOST /v1/freezes/{freezeId}/retry— Retry failed fan-out targets auth: both · scopes: freeze:writeGET /v1/freeze-state— Is this repository, branch or organization frozen? auth: both · scopes: freeze:read
Schedules
GET /v1/schedules— List schedules auth: both · scopes: schedule:readPOST /v1/schedules— Create a schedule auth: both · scopes: schedule:writePOST /v1/schedules/preview— Preview the occurrences of an unsaved schedule draft auth: both · scopes: schedule:readGET /v1/schedules/occurrences— List planned and past occurrences in a time range auth: both · scopes: schedule:readGET /v1/schedules/calendar— Occurrences grouped by day for one month auth: both · scopes: schedule:readPOST /v1/schedules/import— Import a holiday calendar as schedules auth: sessionGET /v1/schedules/{scheduleId}— Get a schedule auth: both · scopes: schedule:readPATCH /v1/schedules/{scheduleId}— Update a schedule and re-materialize its horizon auth: both · scopes: schedule:writeDELETE /v1/schedules/{scheduleId}— Delete a schedule auth: both · scopes: schedule:writeGET /v1/schedules/{scheduleId}/preview— Preview the next occurrences of a saved schedule auth: both · scopes: schedule:readPOST /v1/schedules/{scheduleId}/skip-next— Skip the next planned occurrence auth: both · scopes: schedule:writePOST /v1/schedules/{scheduleId}/run-now— Apply or lift a schedule's window immediately auth: session
Exceptions
GET /v1/exceptions— List exceptions auth: both · scopes: exception:readPOST /v1/exceptions— Grant a per-PR exception (one row per covering freeze) auth: both · scopes: exception:write · requires the pr_exceptions entitlementGET /v1/exceptions/{exceptionId}— Get an exception auth: both · scopes: exception:readPOST /v1/exceptions/{exceptionId}/revoke— Revoke an exception (never entitlement-gated) auth: both · scopes: exception:writeGET /v1/exception-requests— List pending exception requests auth: both · scopes: exception:readPOST /v1/exception-requests— Request an exception for a pull request auth: both · scopes: exception:write · requires the pr_exceptions entitlementPOST /v1/exception-requests/{exceptionId}/decide— Grant or deny an exception request auth: both · scopes: exception:write · requires the pr_exceptions entitlement
Audit
GET /v1/audit— List audit entries (read-time retention filter) auth: both · scopes: audit:readGET /v1/audit/export— Stream the audit log as CSV (hard cap 500 000 rows) auth: both · scopes: audit:read · requires the audit_export entitlementGET /v1/audit/actions— The audit action vocabulary auth: both · scopes: audit:read
API keys
GET /v1/api-keys/scopes— The API key scope vocabulary auth: sessionGET /v1/api-keys— List API keys auth: sessionPOST /v1/api-keys— Create an API key auth: sessionPOST /v1/api-keys/{apiKeyId}/rotate— Rotate an API key with a grace window auth: sessionDELETE /v1/api-keys/{apiKeyId}— Revoke an API key auth: session
Billing
GET /v1/plans— The plan catalog auth: noneGET /v1/billing— Billing summary auth: both · scopes: billing:readGET /v1/billing/prices— Price catalog auth: sessionPOST /v1/billing/checkout— Create a Stripe Checkout session auth: both · scopes: billing:writePOST /v1/billing/portal— Create a Stripe Customer Portal session auth: both · scopes: billing:writePOST /v1/billing/trial— Start the 14-day no-card Business trial auth: both · scopes: billing:writeGET /v1/entitlements— Resolved entitlements, limits and usage auth: both · scopes: repo:read, billing:read