Scope the access
Give each agent its own API key, scoped to exactly the websites and capabilities its job requires. Separate keys keep the audit log attributable and let you revoke one agent without breaking another.
A
content_editor key cannot edit source code, publish the website, or change settings — the MCP server does not even show it those tools. The owner role is not grantable to keys. Rescope a key at any time by sending access to PATCH /v1/apiKeys/{apiKeyId}; the change applies immediately. See Access control and Manage API keys.
For chat assistants such as ChatGPT and Claude, use an OAuth connection to the default MCP endpoint instead of a key. At consent, choose the organization and only the websites the assistant needs. The connection mirrors your own role, so a person with the content_editor role connects a content-only assistant. Keep the full-access endpoint for the rare agent that must administer the account. See Use Cactal in ChatGPT and Claude.
Draft-first editing
All source edits land on the website’s head, the draft version, and nothing an agent writes reaches the live website until an explicitPOST /v1/websiteSourceCode/head/publish. Writes without a leaseToken take the website’s edit lease automatically, and fail with a 409 conflict instead of interleaving when another editor is still working on the website, such as the Cactal agent while it runs or a teammate who changed it in the last 5 minutes. An agent takes over with POST /v1/websiteSourceCode/lease/acquire only when the user agrees.
Review the draft at any time on its preview host:
X-Robots-Tag: noindex, nofollow, so drafts stay out of search engines. CMS items have their own draft state: an agent can prepare items and leave publishing to you. See Preview drafts and versions.
Check before publish
POST /v1/websiteSourceCode/head/check runs the framework quality gate against the draft without publishing anything. Make a passing check a hard precondition in your agent’s instructions, and publish the version that passed: send the version the check returned to POST /v1/websiteSourceCode/head/publish, which refuses with a 409 conflict when the draft changed after the check.
The check answers “does it render,” not only “does it compile.” It server-renders every page using placeholder content synthesized from the CMS schema, and returns each page that threw in renderFailures with its pageId, route, and error. Treat that array as the repair list. See What the head check covers.
Publishing runs a build in an isolated sandbox and creates a deployment that moves through building, then ready or failed. Only a deployment that reaches ready serves traffic — but a failed publish still costs time, so check first.
Put a human at the publish gate
The strongest pattern separates preparation from publication.1
Agent prepares the draft
The agent edits source, content, and assets on head, running
POST /v1/websiteSourceCode/head/check after each batch of changes.2
Agent reports the preview URL
When the check passes, the agent posts
https://draft--<label>.cactal.app and a summary of what changed.3
Human reviews the draft
Open the preview URL, list files changed from the live version with
GET /v1/websiteSourceCode/changes, and inspect selected files with GET /v1/websiteSourceCode/files/diff.4
Publish after approval
Either you publish from the dashboard, or you tell the agent to call
websiteSourceCode_head_publish with the version it checked.- Hard enforcement: give the agent a
content_editorkey. It cannot publish at all; a human (or a separate, human-triggered process) owns the publish step. - Host enforcement: in ChatGPT, Claude, and other MCP hosts, approvals come from the host; keep the tools Cactal marks destructive, such as publishing, set to ask. See Approvals.
- Policy enforcement: give a
full_editorkey plus a standing instruction. Useful when the same agent must build and ship:
cactal-publish-policy.md
Watch the audit log
Lifecycle and access-control operations write organization audit events with actor attribution: website create/rename/delete/restore/transfer, editor grants and invitations, API keys, domains, organization membership, and billing. Actions through an API key carryactorKind: "api_key", so reviewing that activity is one filtered request:
eventType, resourceType, actorPrincipalId, or websiteId (which matches the website itself and resources belonging to it), and page with cursor (see Pagination). Reading the audit log requires an admin-role key or the dashboard.
Source file edits, publishes, CMS content, and asset changes are not audit-logged. Review an agent’s content work where it actually lives:
GET /v1/websiteSourceCode/changes for the pending file list, GET /v1/websiteSourceCode/files/diff for selected source changes, and the draft-- preview for the rendered result.Recover
Every layer of agent work has an undo path. None of these require the agent that caused the problem.
Unpublish needs no edit lease and takes every site hostname offline. Cached pages may take a few minutes to disappear. Rollback changes what serves immediately and moves head to a new copy of the selected historical version. See Roll back and recover for the full procedures, including failed-build recovery.
If a key is compromised
Act on the key first, then investigate.- Rotate with
POST /v1/apiKeys/{apiKeyId}/rotate— the old secret stops working immediately and you receive a new one once. - Revoke with
POST /v1/apiKeys/{apiKeyId}/revokeif the agent should lose access entirely. Revocation is permanent. - Audit what the key did: filter the audit log by
actorKind=api_keyand the key’s principal, then roll back anything unwanted.
A safe agent setup looks like this: one key per agent, website-scoped, least role, or a chat connection limited to the websites it needs; all work on head; publish only the checked version; a human approval step; periodic audit review; and a tested rollback path.