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 both MCP endpoints returns only the tools whose required capability the authenticated principal holds, and every tool declares its capability in its metadata. AI connections use the grants described below; 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 sendingaccess to PATCH /v1/apiKeys/{apiKeyId}:
Organization-scoped access
Website-scoped access
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.
AI connections
An AI connection is what an app such as ChatGPT, Claude, or Claude Code receives when you connect it over OAuth to one of the two MCP endpoints; its tokens work only on that endpoint.
A connection never exceeds your own access and follows it as it changes: if you lose access to one organization, it keeps working in the rest; if you lose access to everything it could use, it stops working until you reconnect and choose again. Change access next to the app under Connected apps in Account settings changes what a default connection can use from its next request, without reconnecting. Disconnecting an app in Account settings under Connected apps cuts it off immediately, even if the app still holds an access token, and removing someone from an organization also cuts their connections to it. Actions through a connection are attributed to the person who connected it.
Only people can create organizations. API keys and AI connections cannot.
See Connect over MCP for the consent flow and Use Cactal in ChatGPT and Claude for connecting a chat assistant.
Cross-tenant requests return 404
Requesting a website — or anything under one: source code, CMS, assets, domains — where you hold no grant returns404 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.
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; AI apps connected, changed, or disconnected; billing changes. Each event records the acting principal (a person or an API key; actions through an AI connection are attributed to the person who connected it), the affected resource, a summary, and a timestamp.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.