Skip to main content
Cactal authorizes every request the same way: a principal — a human member or an API key — holds role grants, roles bundle capabilities, and each operation requires one capability.

Organization roles

An organization member holds exactly one role across the whole organization: Roles are strictly additive down this table. Assign a member’s role with PATCH /v1/organizations/{organizationId}/members/{memberPrincipalId}; bring new members in with organization invitations. See Invite teammates and clients.

Website-scoped editor roles

People outside the organization can be granted access to a single website — the agency-and-client pattern. Two roles exist at website scope: Grant directly with PUT /v1/websites/{websiteId}/editors/{principalId} and body { "role": "full" | "content" }, or add by email with POST /v1/websites/{websiteId}/editors using the same role values. Invitations are pending until accepted or canceled and expire after 48 hours by default (override with expiresAt). If the email already belongs to an account, the grant applies immediately — no invitation email. Directly shared websites appear in the editor’s own Sites navigation — in a “Shared with you” sidebar group and in the unified Sites list — without making them an organization member or revealing anything about the owning organization beyond its name and URL slug. GET /v1/websites?scope=shared lists the same set; each website list item carries a shared flag and its organizationSlug.
Organization members already inherit website access from their organization role. Granting one directly with PUT /v1/websites/{websiteId}/editors/{principalId} returns 400: Organization team members already inherit website access from their org role. Inviting one by email instead returns already_inherited and sends no invitation.

Capabilities

Capabilities are the underlying permission vocabulary — one per operation, named after it: websites.create, cms.items.setPublished, websiteSourceCode.head.publish, auditLog.list. Roles are fixed bundles of capabilities; you assign roles, and Cactal checks capabilities. The same vocabulary drives MCP: tools/list on POST /v1/mcp returns only the tools whose required capability the authenticated principal holds, and every tool declares its capability in its metadata. OAuth uses the signed-in user’s grants; API keys use their configured grants. A content editor never sees the publish tool.

API keys carry the same roles

An API key is a principal with grants, exactly like a member — one of two access shapes, set at creation and changeable by sending access to PATCH /v1/apiKeys/{apiKeyId}:
Organization-scoped access
Website-scoped access
Organization-scoped keys take admin, full_editor, or content_editor. All organization roles can read billing state, including credit usage and balances. The owner role is not grantable to keys, so no key can administer billing, transfer ownership, or delete the organization. Website-scoped keys take full_editor or content_editor across one or more websites, all in the key’s organization, and cannot read organization billing state. Because keys and members resolve through the same grants, enforcement is identical across the dashboard, REST, and MCP. Scope each key to the least access its job needs — a content bot gets { "kind": "websites", ..., "role": "content_editor" }, not an organization role. See Create an API key and Manage API keys.

Cross-tenant requests return 404

Requesting a website — or anything under one: source code, CMS, assets, domains — where you hold no grant returns 404 with Website not found, not 403. Resource ids never confirm their own existence to principals outside the tenant. 403 means something different: you can see the resource’s tenant but your role lacks the capability. For example, a content_editor key calling POST /v1/websiteSourceCode/head/publish gets 403.
For an agent, a 404 on a known-good website id usually means the wrong API key, not a missing website — check which organization and websites the key is scoped to before retrying. A 403 means the key needs a higher role, which a human must grant.

Audit log

Administrative and security-relevant mutations are recorded in the organization audit log: website create, delete, and transfer; editor grants and invitations; API key create, update, rotate, and revoke; custom domain changes; organization membership and invitations; billing changes. Each event records the acting principal — human or API key — the affected resource, a summary, and a timestamp.
Reading the log requires the auditLog.list capability — organization admin or owner, or a key with organization-scoped admin access. Use it to review what an agent did before approving its next run. See Agent-safe publishing.

Constraints

Next steps

Manage API keys

Scoping strategy, rotation, and revocation.

Invite teammates and clients

Organization membership versus website-scoped editors.