Authentication
Asiri authenticates every API request with a bearer token in the Authorization header:
Authorization: Bearer asiri_live_<random>There is no separate key id / secret handshake for external integrations. The entire token is the credential. Treat it like a password.
First-party dashboard clients may also use the Better Auth session cookie, but external integrations should use tenant API keys.
Trust model
- Workspace-scoped. A key only ever sees data from the workspace that minted it. Cross-tenant access is enforced at the database layer via row-level security — see Concepts → RLS.
- Scope-gated. Each key carries explicit external API scopes such as
reports:read,audit:read, orwebhooks:write. Requests outside the public allowlist or granted scopes fail with403 forbidden. See API Keys. - Auditable. Every authenticated call is logged with the key id, scope, route, and request id. See Concepts → Audit log.
Environments
| Environment | Base URL | Key prefix |
|---|---|---|
| Production | https://api.asiri.ng | asiri_live_ |
| Staging | https://api.staging.asiri.ng | asiri_stg_ |
| Development | http://localhost:8000 | asiri_dev_ |
| Test | test runner only | asiri_test_ |
Test keys are sandboxed: they cannot read or write production data, and webhooks fire to your configured staging URL only.
Key rotation
Rotate keys on a schedule (we recommend every 90 days) and immediately on any suspected leak. The dashboard supports overlap windows: mint the new key, redeploy, then revoke the old one.
Errors
| Status | Meaning |
|---|---|
401 | Missing, malformed, or revoked bearer token. |
403 | Token is valid but lacks the required scope. |
429 | Rate limit exceeded — see Retry-After header. |
Error bodies use the canonical envelope:
{
"error": {
"code": "rbac_denied",
"message": "API key external API scopes do not permit: reports:read",
"requestId": "01K..."
}
}