Docs
Scopes & permissions

Scopes & permissions

The full scope catalogue, sensitive vs operational defaults, the strict-mode fine-grained enforcement model, and how to pick the right scopes for your integration.

Construction AI uses a fine-grained scope model. Every API key is granted a set of scopes at creation time, and every request is checked against them. Scopes default to minimal — you grant a key only what it needs, and sensitive scopes default off.

The scope shape

Scopes follow <verb>:<resource> form. The verb is read, write, invoke, or impersonate. The resource is a module name (projects, rfis, drawings, etc.) or a sensitivity category (financial-detail, pricing, purchase-ledger).

Examples:

  • read:projects — read project metadata
  • write:rfis — create or update RFIs
  • read:financial-detail — read CVR, cost reports, payment applications
  • invoke:agent — invoke the AI agent (consumes BYOK Claude tokens)
  • impersonate:user — act as a user other than the key's linked user

A key with ["read:projects", "read:rfis"] can read projects and RFIs and nothing else.

The catalogue

Operational reads (default-on, low sensitivity)

These cover the day-to-day construction data — what most integrations need.

ScopeCovers
read:projectsProject metadata, members, folder tree
read:drawingsDrawing register, revisions, OCR-extracted data, markups
read:specificationsSpecifications, OCR-extracted text
read:rfisRFIs, threads, distributions, attachments
read:communicationsCCIs, RFCs, SIs, RFPs and project correspondence
read:submittalsMaterial submittals, workflows, distributions
read:ramsRisk assessments and method statements
read:programmeSchedules, tasks, baselines, dependencies
read:site-managementSite diary, inspections, snags, photos
read:tender-packagesTender package metadata (no pricing detail)
read:project-knowledgeSemantic search over your project content (consumes Voyage AI quota)
read:settingsCompany contacts, users (name + role), branding
read:libraryLibrary content — schedules, scope templates, prelims, document templates

Financial reads — split by sensitivity

The financial surface is divided into two consent decisions because contract headers and detailed cost data have different sensitivity profiles.

ScopeDefaultCovers
read:financial-headersonPayment application totals, variation agreed values, contract sums (header level)
read:financial-detailoffCVR, margin, internal valuations, variation buildups, cost reports
read:pricingoffTender pricing, master pricing, subcontract pricing, rate book detail, bid comparisons
read:purchase-ledgeroffSupplier commitments, invoices, accruals

The default-off scopes are commercially sensitive — the kind of data a contractor wouldn't share with a third-party vendor by accident. Granting them is an explicit decision at key creation, with a warning shown on the consent screen.

Computational and cross-project

ScopeDefaultCovers
read:analyticsoffComputational tools — reports, summaries, comparisons. Query-budget gated.
read:portfoliooffCross-project aggregations and dashboards. Cross-project visibility — review carefully.

Write scopes (all default-off)

Used by vendor bridges and partner integrations writing canonical data into the platform via the public REST API.

ScopeSensitivity
write:projectsStandard mutation
write:rfisStandard mutation
write:drawingsStandard mutation
write:documentsStandard mutation
write:site-managementStandard mutation
write:submittalsStandard mutation
write:ramsStandard mutation
write:communicationsStandard mutation
write:tender-packagesStandard mutation
write:financial-headersHeader-level financial mutation
write:financial-detailCommercially sensitive mutation
write:pricingCommercially sensitive mutation
write:purchase-ledgerCommercially sensitive mutation
write:libraryLibrary mutation — rate books, pricing schedules, document templates

Identity

ScopeDefaultCovers
impersonate:useroffAllow the key to act as a user other than its linked user, via the X-User-Id header. See Authentication.

BYOK cost

ScopeDefaultCovers
invoke:agentoffInvoke the Construction AI assistant. Consumes BYOK Claude tokens.

How scopes interact with HTTP methods

Two enforcement modes coexist on the platform. Which one applies depends on the route.

Strict mode (sensitive routes)

Routes that touch sensitive data declare a requiredScope at the framework level. The key must hold that exact scope verbatim. Coarse scopes like read do NOT satisfy a fine-grained requirement.

For example, the CVR endpoint requires read:financial-detail:

  • Key with ["read:financial-detail"] → allowed
  • Key with ["read", "read:rfis", "read:drawings"]denied (no read:financial-detail)
  • Key with ["read:financial-detail", "read:rfis"] → allowed

If a key is denied for missing a scope, the response includes the specific scope name:

{
  "success": false,
  "error": "forbidden",
  "message": "API key missing required scope: read:financial-detail"
}

Strict mode is currently applied to 37 sensitive routes covering CVR, cost reports, applications, pricing, and purchase ledger. See the Endpoint reference (coming soon) for the route-by-route mapping.

Legacy coarse mode (operational routes)

Other routes use the legacy coarse-scope model — a backward-compatibility path for existing integrations.

  • Any read* scope (e.g. read, read:rfis, read:projects) grants read access.
  • Any write* scope grants write access.
  • If the key has only module-restricted scopes (e.g. ["read:rfis"]), the route's detected module must match.

This mode is being migrated to strict mode route-by-route as the API surface hardens.

Picking the right scopes — examples

"I want to sync our RFIs from Procore into Construction AI."

You need to write RFIs and probably read projects + members to attach them correctly. Minimum scopes:

["read:projects", "read:settings", "write:rfis"]

"I'm building a Claude desktop integration that summarises overdue RFIs."

Read-only. Need RFIs and probably projects for context. Use the OAuth flow (Claude desktop) which gives you these as default-on:

["read:projects", "read:rfis"]

"I want our internal cost-tracking system to pull CVR data nightly."

This is sensitive. Default-off scopes need explicit grant:

["read:projects", "read:financial-detail"]

"Our procurement system needs to push purchase orders into the platform."

Sensitive write scope:

["read:projects", "read:settings", "write:purchase-ledger"]

"I want a vendor integration that acts on behalf of different users in our org."

The integration needs impersonate:user plus whatever scopes those users' operations need. Set X-User-Id per call:

["read:rfis", "write:rfis", "impersonate:user"]

Scope hygiene

  • Default to minimal. Don't request scopes you don't need. A key with fewer scopes has a smaller blast radius if compromised.
  • One key per integration. Don't share a ["read:rfis", "write:rfis"] key between a sync job and a dashboard. Mint separately.
  • Sensitive scopes are deliberate. If you find yourself routinely granting read:financial-detail to lots of keys, ask whether the integration actually needs detailed financial data or whether read:financial-headers would suffice.
  • Audit periodically. The dashboard shows last-used timestamps. Keys not used in 90 days are candidates for revocation.

What's NOT a scope

Some things look like permissions but are enforced differently:

  • Tenant isolation — not a scope, it's architectural. Every token is scoped to one tenant; cross-tenant queries are physically prevented by row-level security.
  • Project restriction — set at key creation via allowed_projects. The key gets 403 on any project not in the allow-list, regardless of scopes.
  • Rate limits — also set at key creation. See Rate limits.

Where to go next

  • Authentication — how tokens are minted and managed.
  • Rate limits — defaults and headers.
  • Errors — what the platform returns when something goes wrong.