Authentication
All public API endpoints (/api/v1/*) require a Bearer token created in QA Hub's Settings UI.
Create an API token
- Go to Settings → Developer → API Tokens.
- Click Create token.
- Give it a name (e.g., "CI pipeline") and select the scopes you need.
- 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
| Scope | Access |
|---|---|
read | GET endpoints — list projects, cases, runs, results |
write | POST, 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
| Status | Meaning |
|---|---|
401 Unauthorized | Token missing or malformed |
401 Unauthorized | Token not found or revoked |
403 Forbidden | Token lacks required scope |