VeroXM Docs

Authentication

Every v2 Content API request is authenticated with a bearer token issued from a project's API Access settings.

Authorization header
Authorization: Bearer <your-token>

A request with a missing or invalid token is rejected:

401 Unauthorized
{ "error": "Invalid or missing API token" }

A request whose token is valid but lacks the ability the endpoint requires is rejected too:

403 Forbidden
{ "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:

POST /public/v2/projects/:uuid/auth/token
{ "username": "mobile-app", "password": "..." }
200 response
{
  "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:

POST /public/v2/projects/:uuid/auth/refresh
{ "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

VeroXM also serves a v1 API (/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.