import type { Metadata } from "next"; import { CodeBlock } from "@/components/ui/code-block"; import { DocPage } from "@/components/docs/doc-page"; import { A, Code, H2, H3, Li, P, Strong, Table, TBody, Td, Th, THead, Tr, Ul } from "@/components/docs/prose"; import { Callout } from "@/components/docs/callout"; import { Endpoint } from "@/components/docs/endpoint"; import { CodeTabs } from "@/components/docs/code-tabs"; import { ResponseExample } from "@/components/docs/response-example"; import { apiTabs } from "@/components/docs/snippets"; export const metadata: Metadata = { title: "Authentication", description: "API keys, Bearer and X-API-Key headers, scopes, rotation, revocation and the email verification requirement.", }; export default function AuthenticationPage() { return (

API keys

Keys are created in the dashboard under a project. A key belongs to exactly one project and one organization; the requests it makes are logged and counted against them (Fetcha is a private platform with a single unlimited plan, so nothing is billed). The plaintext has a recognisable prefix so you can tell keys apart in configuration:

Prefix Mode Meaning
fch_live_… live Production key. Use it in deployed services.
fch_test_… test Marked as a test key in logs and in GET /v1/me. Behaves like a live key today: requests are real and appear in your usage.

A key is between 20 and 128 characters. Anything else, or a token without one of the two prefixes, is rejected with 401 INVALID_API_KEY before the database is consulted.

Shown once, hashed at rest

The plaintext is displayed a single time when the key is created (or rotated). Fetcha persists only a SHA-256 hash together with the non-secret prefix and last four characters used to identify the key in the dashboard. There is no way to retrieve a lost key; rotate it instead.

Sending the key

Use the standard Bearer scheme. This is what the SDKs send.

If your HTTP client cannot set Authorization, send the key in X-API-Key instead. When both headers are present, X-API-Key takes precedence.

Never ship a key in a browser bundle or mobile app: anyone who can read it can fetch on your behalf, fill your request log and trip your spending limits. Call Fetcha from your backend. The API allows cross-origin requests so that the dashboard can talk to it, not so that keys can live in the browser.

Scopes

Each key has a list of scopes chosen at creation. A request that needs a scope the key lacks is refused with 403 FORBIDDEN and a message naming the missing scope.

Scope Grants Status
fetch:execute POST /v1/fetch Live
sessions:write POST /v1/sessions, DELETE /v1/sessions/:id. Listing and reading sessions requires no scope. Live
usage:read GET /v1/usage Live
browser:use Kept for compatibility. The managed browser is part of POST /v1/fetch and needs only fetch:execute. Compatibility

GET /v1/me and GET /v1/sessions only require a valid key.

Accounts and email verification

Fetcha is invitation-only: an account can only be created with an email address that a Fetcha administrator placed on the access list. Once the account exists, API keys work only after that email address is verified. Until then every authenticated call, including /v1/me, fails with 403 EMAIL_NOT_VERIFIED. Resend the verification email from the dashboard if you did not receive it. The dashboard Playground is exempt so you can try the product before verifying.

Rotation and revocation

  • Rotate replaces the secret of an existing key and shows the new plaintext once. The old plaintext stops working immediately.
  • Revoke disables a key permanently. Requests made with it return 401 INVALID_API_KEY with the message This API key was revoked.
  • Expiry is optional and set in days at creation. Expired keys return 401 INVALID_API_KEY with This API key has expired.

Authenticated principals are cached for up to 30 seconds per API process. The dashboard invalidates the cache when you rotate or revoke, so changes normally apply at once; in the rare case the invalidation is lost, a stale key stops working within 30 seconds.

Other conditions that block a key even when it is valid: the project was archived (403 FORBIDDEN), the organization was suspended (403 FORBIDDEN, contact{" "} support@fetcha.co).

Checking a key

GET /v1/me validates the key and returns the project, organization and key metadata it resolves to. It is the cheapest call you can make and a good health check for your configuration.

Logging and redaction

Fetcha never logs your API key. On the request log, Authorization, Cookie, Set-Cookie, X-API-Key and similar headers that you send to targets are stored as [redacted] when your project log level includes headers. Response bodies are not stored by default.

); }