Authorization & Scopes
Every API request is authenticated by an API key. Keys have two orthogonal authorization axes:
- Scope — what data the key can see (organisation-wide vs a single project).
- Role — what actions the key's owner can perform (determined by the
roleof the user who created the key).
Key Scopes
| Scope | Description | How to create |
|---|---|---|
Organisation (organization) | Can read and write data across all projects in the workspace. | Admin creates in Settings → Developer → API Keys, choosing "Organisation" scope. |
Project (project) | Restricted to a single project. Cannot cross into other projects or access org-wide endpoints. | Admin or engineering-role user creates in Settings → Developer → API Keys, choosing "Project" scope and selecting the project. |
Checking your key's scope
GET /api/v1/me
{
"apiKeyId": "f17d33b9-...",
"scope": "organization",
"scopedProjectId": null,
"permissions": null,
"organizationId": "ec597dd5-..."
}
A project-scoped key will show "scope": "project" and a non-null scopedProjectId. The permissions array lists any additional restrictions applied at key creation time.
Endpoint Scope Requirements
| Endpoint | Org-scoped key | Project-scoped key |
|---|---|---|
GET /me | ✓ | ✓ |
GET /projects | ✓ all projects | ✓ own project only |
POST /projects | ✓ | ✗ 403 scope_violation |
GET /projects/:id/entries | ✓ | ✓ own project only |
POST /projects/:id/entries | ✓ | ✓ own project only |
GET /projects/:id/time-entries | ✓ | ✓ own project only |
POST /projects/:id/time-entries | ✓ | ✓ own project only |
GET /time-entries (org-wide list) | ✓ | ✗ 403 scope_violation |
PATCH /time-entries/:id | ✓ | ✓ own project only |
GET /users | ✓ | ✗ 403 scope_violation |
POST /users/invite | ✓ | ✗ 403 scope_violation |
GET /webhooks | ✓ | ✗ 403 scope_violation |
POST /webhooks | ✓ | ✗ 403 scope_violation |
GET /integration-links | ✓ | ✓ filtered to own project |
GET /audit-events | ✓ | ✓ filtered to own project |
GET /search | ✓ | ✓ filtered to own project |
Role-Required Endpoints
Some write endpoints additionally require the API key's creating user to have a sufficiently privileged role. The role check is performed against the Align role of the user who created the key.
| Endpoint | Minimum role required | Reason |
|---|---|---|
POST /time-entries/:id/approve | manager or admin | Time approval routing — only managers and admins may approve |
POST /time-entries/:id/reject | manager or admin | Time rejection — only managers and admins may reject |
POST /time-entries/:id/unlock | manager or admin | Unlocking a locked entry requires an approver-level role |
POST /users/invite | admin (org-scoped key) | User provisioning requires org admin |
DELETE /projects/:id | admin | Destructive org-level action |
Attempting a role-required action with insufficient role returns:
{ "reason": "forbidden", "message": "Missing write:time_entry permission." }
Inspecting Permissions at Runtime
GET /me returns a permissions array that lists the explicit permission grants on the current key. When permissions is null, the key inherits all default permissions for its scope and the creating user's role.
{
"apiKeyId": "f17d33b9-...",
"scope": "organization",
"scopedProjectId": null,
"permissions": ["read:entry", "write:entry", "read:time_entry"],
"organizationId": "ec597dd5-..."
}
You can use this to verify at startup that your key has the permissions your integration requires, and fail fast with a clear error rather than discovering missing permissions at runtime.
Error Reference
| HTTP | reason | Meaning |
|---|---|---|
401 | missing_key | No auth header present |
401 | invalid_key | Key not recognised |
401 | key_revoked | Key was revoked |
403 | scope_violation | Project-scoped key attempted to access a different project or an org-wide endpoint |
403 | forbidden | Authenticated but the key's role lacks the required permission |
404 | not_found | Resource exists but is not visible to this key's scope (treated as not found to avoid leaking existence) |