Authentication
Every v2 Content API request is authenticated with a bearer token issued from a project's API Access settings.
Authorization: Bearer <your-token>A request with a missing or invalid token is rejected:
{ "error": "Invalid or missing API token" }A request whose token is valid but lacks the ability the endpoint requires is rejected too:
{ "error": "This token cannot perform 'create' actions" }Base URL
Every v2 endpoint is mounted under a project's UUID:
/public/v2/projects/:uuid/...End-user login & refresh tokens
A static token from API Access is right for a server-to-server integration you control. For a case where the API itself needs to authenticate individual end users - a mobile app, a partner integration you don't operate - issue username/password credentials instead and let the caller log in for a short-lived, rotating token pair.
Create a credential on a project's API Access page, with its own scoped abilities, then the caller logs in against the project directly:
{ "username": "mobile-app", "password": "..." }{
"accessToken": "<jwt, 1 hour>",
"refreshToken": "<opaque, 30 days>",
"tokenType": "Bearer",
"expiresIn": 3600,
"abilities": ["read"]
}The accessToken is a short-lived (1 hour) signed JWT - use it exactly like a static API token, as a bearer token on any REST v2 or GraphQL request. When it expires, exchange the refresh token for a new pair instead of asking the user to log in again:
{ "refreshToken": "<the one you were issued>" }The response is a brand-new { accessToken, refreshToken, ... } pair. The refresh token you sent is revoked the instant it is used - refresh tokens are single-use and rotate on every call, so a stolen-and-replayed refresh token stops working the moment the legitimate client refreshes first.
A note on v1
/public/v1/:uuid/...) kept for backward compatibility with older integrations. It uses the same underlying data as v2 but an older, narrower request shape, and isn't documented here - build new integrations against v2.