Authentication
API key format, scopes, brand restriction, and key rotation.
Every request to the Public API authenticates with an opaque bearer token in
the Authorization header. Browser CORS calls are blocked at the edge, so the
API is server-to-server only.
The header
curl https://api.rankprompt.com/v1/me \
-H "Authorization: Bearer rp_live_YOUR_KEY"const res = await fetch('https://api.rankprompt.com/v1/me', {
headers: { Authorization: `Bearer ${process.env.RANKPROMPT_API_KEY}` },
});
const me = await res.json();import os, httpx
res = httpx.get(
"https://api.rankprompt.com/v1/me",
headers={"Authorization": f"Bearer {os.environ['RANKPROMPT_API_KEY']}"},
timeout=30,
)
res.raise_for_status()
me = res.json()Keys are prefixed with rp_live_ so they are easy to detect in logs and pull
requests. We submit the prefix to GitHub secret scanning so leaks are caught
automatically.
Scopes
Scopes are granular per resource. The implication hierarchy is:
* ⊃ read:all / write:all ⊃ specific scopes; write:foo ⊃ read:foo.
| Scope | Grants |
|---|---|
read:all | Read access to every resource type. |
write:all | Read + write access to every resource type. |
read:brands | List and inspect brands. |
write:brands | Create, update, and delete brands (implies read). |
read:reports | List and inspect reports. |
write:reports | Create, update, and delete reports (implies read). |
write:prompts | Create, update, and delete prompts (implies read). |
read:jobs | List and inspect jobs. |
write:jobs | Create, update, and delete jobs (implies read). |
read:region-configs | List and inspect region-configs. |
write:region-configs | Create, update, and delete region-configs (implies read). |
read:scheduled | List and inspect scheduled. |
write:scheduled | Create, update, and delete scheduled (implies read). |
read:white-label | List and inspect white-label. |
write:white-label | Create, update, and delete white-label (implies read). |
read:citations | List and inspect citations. |
read:meta | List and inspect meta. |
read:meta and GET /v1/me
GET /v1/me is the introspection endpoint that confirms your credentials
work. It always returns user_id, auth_type and plan. The fields that
describe what your key can do (key_prefix, scopes,
allowed_brand_id) are only included when the key carries the
read:meta scope.
When a request lands with insufficient scope you get back the
insufficient_scope error from the error catalog: a 403
whose details carry both the missing scope (required_scope) and the
scopes your key actually has (key_scopes):
{
"error": {
"code": "insufficient_scope",
"message": "This endpoint requires the 'write:brands' scope",
"details": {
"required_scope": "write:brands",
"key_scopes": ["read:brands"]
}
},
"request_id": "01HZK3..."
}
Brand restriction
Optionally bind a key to a single brand at creation time
(allowed_brand_id). The API will then refuse any request whose target brand
does not match, even if the calling key carries write:all. This lets you
issue per-brand keys to clients without having to spin up a new Rank Prompt
workspace.
A request that crosses the boundary fails with brand_not_authorized (403).
Lifecycle: create, rotate, revoke
Manage keys from the Developers page inside your workspace. Common operations:
- Create: pick scopes, optional brand restriction, and optional expiry. The full key is shown once at creation time and never again.
- Rotate: create a new key, deploy it, then revoke the old one. There is no “regenerate” button on purpose. Explicit rotation makes overlapping keys the default and prevents downtime.
- Revoke: disables the key immediately. In-flight requests still complete;
the next call returns
invalid_api_key. - Expire: keys with an
expires_atstart returningexpired_api_keyonce the timestamp passes. Use this for short-lived integrations.
Storage hygiene
- Treat keys like database passwords. Never commit them, never log them, never put them in client-side code.
- Prefer your platform’s secret manager (AWS Secrets Manager, GCP Secret Manager, Vercel/Netlify env vars, Doppler, 1Password CLI).
- Rotate immediately on suspected exposure; we cannot revoke retroactively what has already been read from your codebase.