Base URL
Each Frontic project gets its own Fetch subdomain that embeds the project’s identifier. The URL pattern is:.frontic/generated-client.ts).
A complete request URL is the base plus the route - e.g. https://fetch-{project-token}.frontic.com/listing/<listing-slug>.
Available Endpoints
Fetch a Block
POST /block// - single record by key
Fetch a Listing
POST /listing/ - search, filter, sort, paginate a collection
Fetch a Page
GET /page/ - page by full URL
Fetch a Tree
POST /tree/ - hierarchical records (Preview)
Get Context
GET /context/token - resolve a contextKey
List Contexts
GET /context - available context variations for the project
Update Context
PATCH /context - change the active region/locale on a contextKey
Authentication
The Fetch API does not use the standardAuthorization header. Auth is split across two concerns:
- Context resolution - every request needs to resolve to a (scope, region, locale) triple. Send either
fs-context(acontextKey) orfs-domain(a configured project domain). If neither is sent, the project’s default region and locale apply. - Secret-based access control - the
fs-secretheader gates the API when fetch secrets are configured for the project.
The “Authorization required” label that appears in the playground above is inherited from the docs site’s global API config - it doesn’t apply to the Fetch API. Use the
fs-* headers below.Fetch API secrets
Fetch secrets turn your project’s Fetch API from open (anyone with the URL can call it) into secret-protected (every request must includefs-secret). Whether you need them depends on how your frontend reaches the API:
- Server-side or proxied calls - keep the Fetch API closed and require a secret. Your server holds it; it never reaches the browser.
- Direct browser calls - the open default is fine if your frontend talks to the Fetch API straight from the browser. There’s nothing for the browser to keep secret anyway. If that’s not acceptable for your project, route those calls through a server-side proxy and apply a secret there instead.
develop, so a new secret protects develop at once and reaches preview and public only when Release Control carries it forward - a storefront pointed at public keeps answering unprotected until that release lands. The value travels unchanged, so one secret then works against all three stages.
The same Add API Key dialog also creates Ingest API keys and the project’s Bypass Token, which identifies Frontic to your own storefront rather than protecting the Fetch API.
Using the secret
How you attachfs-secret depends on what’s calling the API:
To rotate, add the new secret first, redeploy your servers/proxies with the new value, then remove the old one - keep both active for the cut-over.
Headers
Most endpoints support the same set; per-endpoint pages list which are honoured. None of the context-resolution headers are required - without them, Frontic falls back to the project’s default region and locale. In production you’ll almost always want to send one offs-context or fs-domain so the response is shaped for the right visitor.
Response headers
Frontic adds the following on every successful response:Context resolution
Every request resolves to a single (scope, region, locale) triple before any data is read:- If
fs-contextis set and points to an existing context, the stored values are used. - Else if
fs-domainis set, the configured domain mapping resolves scope / region / locale. - Otherwise, the project’s default region and locale apply.
fs-context is sent but doesn’t match an existing context (and is a valid 36–50-character token), Frontic creates one on the fly using the resolved (scope, region, locale) and stores it under that token. Subsequent requests with the same token re-use the stored context.
See Request Context for the full lifecycle.
Response shape
Block, listing, and tree endpoints return JSON shaped by your project’s Detail Block or Search Listing configuration. The exact shape is project-specific - generate the Client SDK to get typed responses, or keep the OpenAPI spec it is built from to inspect it raw. The Page endpoint and the context endpoints return fixed shapes documented on each page.Errors
Errors return a JSON body in one of two shapes. A deliberate error - a missing record, a failed validation - carries acode:
error- a human-readable message.code- a machine-readable error code. Branch on this, not onerror.details- structured context for the error. Its shape varies by code, and it is empty for most.correlationId- identifies the request. Include it when you contact support. Empty when the request failed before it could be identified, for example with an unknown project or an invalid token.
500) carries only error and correlationId - no code, no details. The presence of code is how you tell the two apart.
Both shapes are described in your project’s OpenAPI spec, so the generated Client SDK and the Nuxt module type them for you.
Common HTTP statuses you’ll see:
Validation failures answer
422, not 400 - including a malformed body. Plan limits answer 422 as well, not 403.
OpenAPI spec
Your project’s OpenAPI spec enumerates every block, listing, tree, and page endpoint defined in the project, with its response shape, plus the shared context endpoints and the error bodies.frontic generate fetches it from Frontic’s API, scoped to the selected project, and builds the typed Client SDK from it. To keep a copy, run it with --persist-oas: it writes fetch-api.spec.yaml next to the generated files, which you can inspect or feed to OpenAPI generators in other languages.
The Fetch subdomain also serves an OpenAPI document at https://fetch-{project-token}.frontic.com/api/doc.json. That one is generic: it describes the Fetch API’s routes with the block or listing name as a path parameter, not your project’s endpoints or their response shapes, and the Client SDK isn’t built from it.