Skip to main content

Authentication

All public API endpoints (/api/v1/*) require a Bearer token created in QA Hub's Settings UI.

Create an API token

  1. Go to Settings → Developer → API Tokens.
  2. Click Create token.
  3. Give it a name (e.g., "CI pipeline") and select the scopes you need.
  4. Copy the token — it is shown only once. Store it in a secret manager or CI environment variable.

Tokens have the format qh_<prefix>_<secret>. The prefix is stored in plaintext for display; the secret is hashed with bcrypt and never retrievable again.

Scopes

ScopeAccess
readGET endpoints — list projects, cases, runs, results
writePOST, PATCH, DELETE endpoints — create and modify resources

Assign only the scopes a token needs. CI pipelines that only ingest results need write. Reporting tools that only read metrics need read.

Making requests

Add the token to every request in the Authorization header:

Authorization: Bearer qh_abc123_your-secret-here

cURL example

curl https://your-qahub.com/api/v1/projects \
-H "Authorization: Bearer qh_abc123_yoursecret"

JavaScript (fetch)

const res = await fetch('https://your-qahub.com/api/v1/projects', {
headers: {
'Authorization': 'Bearer qh_abc123_yoursecret',
'Content-Type': 'application/json',
},
});
const { data } = await res.json();

Verify a token

Use the /api/v1/me endpoint to confirm a token is valid and inspect its scopes:

curl https://your-qahub.com/api/v1/me \
-H "Authorization: Bearer qh_abc123_yoursecret"
{
"tenant": { "id": "cuid123", "name": "Acme Corp", "status": "ACTIVE" },
"scopes": ["read", "write"],
"ai": { "provider": "gemini", "model": "gemini-2.0-flash", "quota_exhausted": false }
}

Token scoping

Tokens are tenant-scoped — a token created by a user in the Acme Corp workspace can only access Acme Corp data. There is no cross-tenant access via tokens.

Revoking a token

Go to Settings → Developer → API Tokens, find the token by its name/prefix, and click Revoke. The token stops working immediately.

Error responses

StatusMeaning
401 UnauthorizedToken missing or malformed
401 UnauthorizedToken not found or revoked
403 ForbiddenToken lacks required scope