Appearance
Scopes
OAuth access tokens carry scopes — strings declaring which categories of data the token can read or write. The API checks the scope on every request and rejects calls that aren't covered.
Direct kAuth bypasses scopes
The direct kAuth path always grants the admin meta-scope. This page is about OAuth tokens.
Naming
Scopes follow the pattern {resource}:{action}:
{resource}— the URL slug (e.g.projects,invoices,time-entries){action}— eitherread(GET, POST/query) orwrite(POST, PATCH, DELETE)
A token with projects:read can list and fetch projects but cannot create or modify them.
Meta-scopes
Three scopes expand to broader sets:
| Scope | Expands to |
|---|---|
admin | Everything below — full read and write across every resource. |
read | Every {resource}:read scope. |
write | Every {resource}:read and {resource}:write scope. |
If a token has any meta-scope, it can hit any endpoint that meta-scope covers — you don't have to list every individual scope.
Per-resource scopes
| Resource | Read scope | Write scope |
|---|---|---|
| Projects | projects:read | projects:write |
| List Items | list-items:read | list-items:write |
| Invoices | invoices:read | invoices:write |
| AIA Invoices | aia-invoices:read | aia-invoices:write |
| Contracts | contracts:read | contracts:write |
| Clients | clients:read | clients:write |
| Vendors | vendors:read | vendors:write |
| Milestones | milestones:read | milestones:write |
| Tasks | (uses projects:*) | (uses projects:*) |
| Allocations | allocations:read | allocations:write |
| Payments | payments:read | payments:write |
| Purchases | purchases:read | purchases:write |
| Purchase Items | purchase-items:read | purchase-items:write |
| Items (Catalog) | items:read | items:write |
| Documents | documents:read | documents:write |
| Bills | bills:read | bills:write |
| Departments | departments:read | departments:write |
| Resources | resources:read | resources:write |
| Submittals | submittals:read | submittals:write |
| Assets | assets:read | assets:write |
| Service Tickets | service-tickets:read | service-tickets:write |
| Time Entries | time-entries:read | time-entries:write |
| Billables | billables:read | billables:write |
| Users | users:read | users:write |
Identity / utility scopes
These cover the standard OIDC identity endpoints and don't gate any resource:
| Scope | Purpose |
|---|---|
openid | Identifies the token as an OIDC ID token request. Required if you want an id_token from the authorization endpoint. |
profile | Include the user's profile info in the ID token. |
offline_access | Issue a refresh token alongside the access token. Required if you want managed refresh. |
GET /api/v2/me, /company, /settings, and /valid don't require any specific scope — any authenticated request can hit them.
Requesting scopes
In any OAuth flow, list scopes in the scope parameter (space-separated):
Authorization Code:
http
GET /oauth/auth?
response_type=code&
client_id=YOUR_CLIENT&
redirect_uri=...&
scope=openid+offline_access+projects:read+invoices:read&
...Client Credentials:
http
POST /oauth/token
grant_type=client_credentials
client_id=YOUR_CLIENT
client_secret=YOUR_SECRET
scope=projects:read+invoices:readThe granted scopes are the intersection of:
- What you requested
- What the OAuth client is configured to allow (set in the developers portal)
- For user-authorized flows, what the user consented to during the authorization screen
Inspect the granted scopes on a token via GET /api/v2/me or by decoding the access token JWT.
Legacy v1 scopes
Three resources were renamed for v2; the legacy scope names still exist (the v1 surface uses them) but new clients should request the v2 scope names:
| Legacy (v1) | Modern (v2) | Reason |
|---|---|---|
tickets:* | service-tickets:* | Clearer in OpenAPI docs |
time:* | time-entries:* | "time" was ambiguous |
items:* (in v1 meaning ServiceCatalog) | items:* (still, same model) + new purchase-items:* for the previously-bundled PO line items | Cleared up a slug collision |
A token granted tickets:read can read v1 ticket endpoints but won't satisfy service-tickets:read on v2 unless you also include a meta-scope. The practical answer: request both forms during the transition, or request the read meta-scope and cover everything.
Granting scopes to a client
Scopes a client is allowed to request are configured per-client in the developers portal under Clients → Edit → Scopes. The token's effective scope is always a subset of what the client is configured to allow.
Principle of least privilege
Don't ask for admin if you only need projects:read. Narrower scopes mean less blast radius if a token is leaked, easier security review, and a better experience for users on the consent screen.