Skip to content

Authentication ​

Every call to the public API carries an organization API token — a credential that starts with atk_. There is no OAuth flow, no session and no user: the token is the identity, and it belongs to the organization, not to the person who created it.

1. Create a token ​

In Studio, open Settings → API tokens and click Create. Choose:

  • a title you will recognize in the activity log (site-build, import-script);
  • a scope — read (default) or read + write (see Scopes);
  • a project — the token is narrowed to it, or All projects for an organization-wide token;
  • an optional expiry — a date means valid through that day.

The full token is shown once. Copy it into your secret store; Studio keeps only a hash and the first characters for display. A lost token is regenerated (same title, scope and project; the old secret dies at once) or revoked.

Least privilege

Create one token per consumer, narrowed to the project it needs. A leaked site-build token should not be able to write, and a leaked import token should not reach every project.

2. Send it ​

Either header works; use one, not both:

bash
curl https://api.hypervalent.io/v1/orgs/YOUR_ORG_ID/token \
  -H "Authorization: Bearer atk_YOUR_TOKEN"
bash
curl https://api.hypervalent.io/v1/orgs/YOUR_ORG_ID/token \
  -H "X-API-Key: atk_YOUR_TOKEN"

The token travels in a header, never a cookie and never a query string. Public reads answer permissive no-credential CORS, so calling from a browser works — but a token in client-side code is visible to everyone who loads the page. Use a build step or a server for anything but a read token whose exposure you accept.

3. Check what it can do ​

GET /orgs/{org_id}/token answers the token's own view of itself:

json
{
  "token": {
    "prefix": "atk_3f9a1c2e",
    "title": "site-build",
    "scope": "read",
    "projectUuid": "…",
    "projectSlug": "marketing",
    "expiresAt": null
  },
  "features": { "mcpServer": true, "apiTokensWrite": false, "removeBranding": false }
}

features.apiTokensWrite is whether this token may write today — its scope is read_writeand the organization's plan still includes API writes. A read_write token on a downgraded plan keeps authenticating but every write answers 403 FEATURE_DISABLED with requiredPlan.

GET /orgs/{org_id}/projects lists the projects the token may name in a URL: every live project for an organization-wide token, exactly one for a narrowed token.

Scopes ​

ScopeMayPlan
readEvery GET — published content, structure, settings, design tokensEvery plan
read_writeEverything read may, plus: create and edit documents and terms, publish / unpublish / trash documents, upload images, and read the working view (?status=draft)Team and above

Scope is enforced twice: the authenticator refuses a non-GET method from a read token (403 TOKEN_SCOPE_READ_ONLY), and every write route re-checks the scope and the plan at use.

A token never carries a user's permissions. What a Studio member may do has no bearing on what a token may do, and revoking a member does not revoke the tokens they created.

Organization and project scoping ​

The URL names an organization (org_id) and usually a project (projectSlug). The server checks, in this order:

  1. Credential — missing → 401 API_TOKEN_REQUIRED; unknown, revoked or expired → 401 INVALID_API_TOKEN. This runs before the URL is resolved, so an anonymous caller cannot use 404-vs-401 to discover which org ids or project slugs exist.
  2. Organization — the token must belong to the URL's organization → 403 TOKEN_ORG_MISMATCH.
  3. Project — a narrowed token must match the URL's project → 403 TOKEN_PROJECT_MISMATCH. An unknown project slug is a plain 404.
  4. Delivery gate — a closed organization (403 ACCOUNT_CLOSED), one whose delivery the platform has blocked (403 DELIVERY_BLOCKED), or one terminated for non-payment (402 BILLING_TERMINATED).

Only then does the read or write run.

Expiry, rotation and revocation ​

  • An expired token is refused exactly like a revoked one (401 INVALID_API_TOKEN). Owners and admins are emailed ahead of an expiry; watch the token list in Studio for the expired state.
  • Regenerate rotates the secret in place — the token keeps its uuid, title, scope, project and expiry, so nothing but the secret in your config changes.
  • Revoke is immediate and permanent. Create a new token rather than trying to reuse one.
  • Every create, regenerate and revoke — and every write made with a token — is recorded in Studio → Activity, attributed to the token by title and prefix.

Documentation for Hypervalent Studio