---
title: "Set up the Writavo MCP server"
description: "Connect Claude, ChatGPT, Cursor, VS Code, Codex or any MCP client to your Site: exact setup per client, sign-in, and every refusal explained."
canonical: "https://writavo.com/docs/mcp"
last-updated: "2026-09-29"
---

# Set up the Writavo MCP server

Let Claude, ChatGPT, Cursor or any MCP client work on your Site. One URL and a browser sign-in: nothing to install, no key to paste.

## Connect in three steps

server url:

```
https://mcp.writavo.com/mcp
```

1. **Add the server.** Find your client [below](#clients) and run its command or add its file.
2. **Sign in.** Your client opens Writavo in the browser. Sign in, pick the Site and the permissions, and approve.
3. **Check it.** Ask the assistant to call `get_site_info` and `verify_api_key`. No Writavo tools? Restart the client or start a new session.

- Hosted only: there is no package to install.
- Streamable HTTP with OAuth 2.1 (dynamic client registration or client ID metadata documents, PKCE S256). Discovery starts from the `401` on `/mcp`, which names `https://mcp.writavo.com/.well-known/oauth-protected-resource`. OAuth scopes are not used: permissions are picked on the sign-in page.

## Add the hosted server

#### Claude Code

Run this, then type `/mcp` in Claude Code, choose `writavo` and sign in. Scope: `-s local` (default) is this project, for you; `-s user` is every project; `-s project` shares it through `.mcp.json`.

shell:

```
claude mcp add --transport http writavo https://mcp.writavo.com/mcp
```

.mcp.json (project scope):

```json
{
  "mcpServers": {
    "writavo": {
      "type": "http",
      "url": "https://mcp.writavo.com/mcp"
    }
  }
}
```

**Or install the plugin** from the public [SparkleOfficial/writavo-mcp-server](https://github.com/SparkleOfficial/writavo-mcp-server) marketplace. It adds the server and the Writavo agent skill; sign in with `/mcp` afterwards.

shell:

```
claude plugin marketplace add SparkleOfficial/writavo-mcp-server
claude plugin install writavo@writavo
```

#### Claude (claude.ai and Claude Desktop)

1. Customize > Connectors > "+" > Add custom connector.
2. Name: Writavo. URL: `https://mcp.writavo.com/mcp`. Leave the advanced OAuth fields empty.
3. Add, then Connect, and sign in.
4. In a chat, turn it on from "+" > Connectors.

On Team or Enterprise, an owner adds it once under Organization settings > Connectors; each member then connects their own account.

#### ChatGPT

Web only, on Plus, Pro, Business, Enterprise and Edu.

1. Settings > Security and login: turn on Developer mode (on Business, Enterprise or Edu an admin must allow it first).
2. Open `https://chatgpt.com/plugins` and choose "+".
3. Name: Writavo. Description: my Writavo Site's blog content. URL: `https://mcp.writavo.com/mcp`. Authentication: OAuth.
4. Create it, then sign in.

#### Codex CLI

Adding it starts the sign-in. If it did not, or the sign-in lapsed: `codex mcp login writavo`.

shell:

```
codex mcp add writavo --url https://mcp.writavo.com/mcp
```

~/.codex/config.toml:

```
[mcp_servers.writavo]
url = "https://mcp.writavo.com/mcp"
```

#### Cursor

[Add Writavo to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=writavo&config=eyJ1cmwiOiJodHRwczovL21jcC53cml0YXZvLmNvbS9tY3AifQ==) in one click, or put this in `~/.cursor/mcp.json` (every project) or `.cursor/mcp.json` (this project). Sign in when Cursor asks.

mcp.json:

```json
{
  "mcpServers": {
    "writavo": {
      "url": "https://mcp.writavo.com/mcp"
    }
  }
}
```

#### VS Code (GitHub Copilot agent mode)

[Add Writavo to VS Code](vscode:mcp/install?%7B%22name%22%3A%22writavo%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.writavo.com%2Fmcp%22%7D) in one click, or use `.vscode/mcp.json` ("MCP: Open User Configuration" for every workspace) or the command. Sign in when VS Code first connects.

.vscode/mcp.json:

```json
{
  "servers": {
    "writavo": {
      "type": "http",
      "url": "https://mcp.writavo.com/mcp"
    }
  }
}
```

shell:

```
code --add-mcp '{"name":"writavo","type":"http","url":"https://mcp.writavo.com/mcp"}'
```

#### Gemini CLI

Add it, then run `/mcp auth writavo` in Gemini CLI. In `settings.json` use `httpUrl` (`url` means the older SSE transport).

shell:

```
gemini mcp add --transport http -s user writavo https://mcp.writavo.com/mcp
```

~/.gemini/settings.json:

```json
{
  "mcpServers": {
    "writavo": {
      "httpUrl": "https://mcp.writavo.com/mcp"
    }
  }
}
```

#### Windsurf

Cascade panel > "..." > Open MCP config file. Add this, save, and sign in when asked.

mcp_config.json:

```json
{
  "mcpServers": {
    "writavo": {
      "serverUrl": "https://mcp.writavo.com/mcp"
    }
  }
}
```

#### Zed

Settings > AI > MCP Servers > Add Server > Add Remote Server, or add this to `settings.json`. Sign in when asked.

settings.json:

```json
{
  "context_servers": {
    "writavo": {
      "url": "https://mcp.writavo.com/mcp"
    }
  }
}
```

#### Any other client

Add `https://mcp.writavo.com/mcp` as a Streamable HTTP server with OAuth; the client discovers the rest.

Without OAuth, send a Writavo secret key: `Authorization: Bearer wv_sk_...`. A key made by hand is not an AI agent key, so the permissions picker and the off switch do not apply to it. Approvals and the call log still do: any key used through MCP is treated as an agent's. Prefer the sign-in.

## If you are an AI assistant asked to install Writavo

> Tell the person what you are doing at each step. Run your client's command or file from [Add the hosted server](#clients) (for claude.ai, ChatGPT or Claude Desktop, give the person those clicks). Let them sign in. Then call `get_site_info` and `verify_api_key` and tell them the Site and what you can and cannot do there. If anything fails, follow [Troubleshooting](#troubleshooting); never retry in a loop.

## Permissions

Per area: No access, Read, or Read and write (Site details are always readable). The organisation's default is Read everywhere except Outreach contacts and Reader comments (on only when picked), plus Read and write for articles, content types and entries, categories, tags, authors, media and Site settings.

| Area | Read and write allows | Costs |
|---|---|---|
| Articles | create, edit, publish, schedule, unpublish, delete; with permission, import a moved blog's views, reactions and shares | no |
| Content types and entries | create, edit, publish, schedule, delete entries; with permission, change types and fields | no |
| Categories, tags, authors | create, edit, delete | no |
| Media | upload, delete images | no |
| AI pipeline ("Read, plan and run") | edit the content plan, start runs, send an article back for a rewrite; with permission, change configuration, prompts and formats | credits |
| Site settings and design | Site settings, knowledge profile, hosted site branding, visitor analytics on or off and its counted domains | no |
| Publishing and domains | reverse proxy, connect or remove a custom domain, publish the hosted site; with permission, disconnect or push to an external CMS | custom domain, 5 US dollars a month |
| SEO | curate competitors, keywords, gaps, backlinks, opportunities; run paid scans | paid scans |
| Outreach contacts | read only: readiness, contacts, campaigns, threads | no |
| Reader comments ("Read and moderate") | turn on or off, approve, reply, mark spam, delete, erase a commenter's comments (needs the person's own Moderate comments permission) | no |
| Team and organisation | invite, change roles, remove members; with permission, change permissions and rename the organisation | no |
| Billing | start a credit pack purchase, change auto-refill and the Site's credit cap, keep the current plan | yes |
| Reports and logs | read only: overview, costs, visitor analytics and its install check, logs | no |

- Which of these need a person's approval: [Approvals](#approvals).
- An assistant can never manage API keys or webhooks, and never gets more than the person who approved it.
- To change a connection's permissions, or add one created after it was made: Settings > AI agents, the connection, Permissions (or Add). Same connection, no new sign-in.
- Owners and admins set the default in Settings > AI agents > Default permissions for new connections. See [AI agent access](/docs/agents).

## Approvals and confirmations

Two separate checks; an assistant must handle both.

**1. Confirm in the chat.** Tools that publish, schedule, unpublish, delete, import or spend credits first reply "Nothing has been done". Call again with `confirm: true` only if the person agrees.

**2. Approve in the dashboard.** Applies to every MCP request, even with a key made by hand:

- **Always:** spending money or credits (pipeline runs, turning the pipeline up, AI rewrites, paid SEO scans, a custom domain, turning auto-refill on, a higher or removed credit cap, keeping the plan); every team change (only the person whose assistant asked can approve it); every live-site change (reverse proxy, connecting or removing a custom domain, publishing the hosted blog, disconnecting or pushing to an external CMS); deleting an article format.
- **While the organisation requires approvals (the default):** deleting an article, category, tag, author or media file; unpublishing an article.

The tool replies with a link and an approval id. Then:

1. **Give the person the link exactly as returned.** `https://app.writavo.com/approvals/<id>` with `?site=<id>`, so it opens on the right Site. Nothing has happened yet.
2. **Wait until they say they approved it.** Do not poll or retry in a loop.
3. **Call the same tool again, same arguments, plus `approval_id`.** An approval works once, for that exact request, for 24 hours. If what the request would do has changed, it is refused (`409 APPROVAL_INVALID`): ask again.
4. **If they denied it, stop.** Ask what they want instead. Never rephrase the request to get around it.

## Settings, delivery, SEO, analytics, comments, team and billing

Articles, categories, tags, authors, media and pipeline runs have their own tools. Everything else in the dashboard goes through three:

- `search_writavo_actions`: describe the task ("connect a custom domain", "pending comments"). Returns matching operations with their operationId, inputs, cost and whether they need approval.
- `read_writavo_action`: runs a GET by operationId. Never changes anything, so a client can allow it without asking.
- `run_writavo_action`: runs anything that changes something. Add `approval_id` when repeating an approved request. Spending money asks you to confirm with the person first.

Per area: [Settings and administration](/docs/administration), [Visitor analytics](/docs/analytics), [Reader comments](/docs/comments).

## Troubleshooting

Every tool reply also includes its own next step.

| If you see | Do this |
|---|---|
| No Writavo tools | Restart the client or start a new session (Claude Code: check `/mcp`). |
| "Needs authentication" or "no credentials" | Sign in: `/mcp` (Claude Code), `codex mcp login writavo`, `/mcp auth writavo` (Gemini CLI), or Connect (claude.ai, ChatGPT). |
| "This sign-in could not be confirmed in this browser" | It was approved in a different browser. Start again and approve in the window the client opened, never in another browser or device. |
| "This sign-in has expired" | Used, or over 30 minutes old. Start again. |
| Sent to create a Site | No Site yet: finish onboarding at `https://app.writavo.com/onboarding`; it returns to the sign-in. |
| A Site or permission cannot be chosen | Agent access is off for that organisation, you cannot manage API keys there, or your role lacks the permission. Pick what is available, or an owner or admin turns agent access on or connects the assistant. |
| Platform admin, no Site listed | Only Sites the account is a member of are listed. Use a member account. |
| `403 INSUFFICIENT_SCOPE` | Tell the person which area needs Read and write; they add it to the same connection in Settings > AI agents. |
| `403 AGENT_ACCESS_DISABLED` | An owner or admin turns agent access on in Settings > AI agents. Do not retry until then. |
| `403 FORBIDDEN` | No permission allows it (the person's own access, ownership, a higher role). Pass on the message; a person makes the change on the dashboard page it names. |
| `409 PREREQUISITE_MISSING` | Set up what it names first (for example a primary domain or a competitor), or ask the person, then retry. Nothing was charged. |
| `409 FEATURE_UNAVAILABLE` | Switched off by Writavo: paid backlink data, or "Spending is paused" (the plan has no daily spend cap configured). Use the free alternative named; for "Spending is paused" the person contacts https://writavo.com/support. Do not retry. |
| `428 APPROVAL_REQUIRED` or `APPROVAL_PENDING` | Give the person the link, wait until they approve, call again with `approval_id`. |
| `403 APPROVAL_DENIED` | Stop, tell them, ask what they want instead. |
| `409 APPROVAL_INVALID` | Expired, used, other arguments, or what it would do changed. Call again without `approval_id` for a new link, and tell the person. |
| `401 API_KEY_REVOKED`, `API_KEY_EXPIRED` or `INVALID_API_KEY` | Sign in again: remove and re-add the connection, or re-authenticate it. |
| `402 PAYMENT_METHOD_REQUIRED` | The Site used its included CMS allowance and has no card: the person adds one in Billing. Not a plan limit; published content keeps serving. |
| `402 NOT_ENTITLED`, `INSUFFICIENT_CREDITS` or `SPEND_CAP_REACHED` | The AI pipeline cannot run (plan, credits or spend cap). Report which; do not retry. Only the person can change it, in Billing. |
| `429 RATE_LIMIT_EXCEEDED` | Wait for `Retry-After`, then go slower. The tools already retry once. |
| `409 CONFLICT` from `schedule_article` | The article is live; scheduling would take it down. Ask the person. `cancel_article_schedule` never takes a live article down. |
| `409 SLUG_CONFLICT` | Slug taken. Ask the person; never invent a new slug for an imported article. |
| `412 PRECONDITION_FAILED` | Edited since you read it: read again, reapply, retry. |
| `404 NOT_FOUND` | Not on this Site (a connection only sees its own). Check the id. |
| `503 MAINTENANCE` | Writes are paused. Wait for `Retry-After`; the published blog keeps serving. |

All error codes: [errors page](/docs/errors).

## Updating a connected assistant

- **Updates** go live for everyone and logins are kept. For new tools, reconnect: `/mcp` > Reconnect in Claude Code (or a new session); restart the session or server entry elsewhere.
- **New permissions** are not added to existing connections. The person adds them in Settings > AI agents (Add or Permissions), or with Scopes in Settings > API keys. No new sign-in.
- **Signing in again** (a reinstall, a new machine) makes a NEW connection and key; it still reaches the Site's stored imports. Revoke old ones in Settings > AI agents. It is only needed if the connection was revoked, expired or turned off.
- An assistant cannot widen its own access. `verify_api_key` shows what it has.

## What the account owner controls

- **Listing:** every connection appears in Settings > AI agents and Settings > API keys (AI agent badge), named after the app, for example "Claude Code (hosted MCP)".
- **Revoke** it there; it stops on its next request.
- **Off switch:** Settings > AI agents > Allow AI agents turns every agent connection in the organisation off, and back on with no new sign-in.
- **Call log:** every request, refusals included (tool, operation, outcome, duration). Kept 90 days.
- **Expiry:** 90 days after issue, extended while in use (within 30 days of expiry, the next use moves it to 90 days from then), never past 365 days from creation. Then sign in again.
- Full guide: [AI agent access](/docs/agents).

## Security

- A connection is a Writavo secret key per Site, labelled as an AI agent key. You choose its Sites at sign-in (one, several, or all, including future ones). An assistant cannot reach any other Site; only the person who connected it changes its Sites, in Settings > AI agents.
- The key is generated and kept on Writavo's servers, encrypted inside the sign-in grant, and never leaves them. The assistant only holds OAuth tokens (an access token lasts one hour). The key is masked out of every reply, log line and error.
- A sign-in must be started and approved in the same browser, so nobody can connect their assistant to your Site with a sign-in link they started.
- Revoke any connection at any time in Settings > AI agents or Settings > API keys.

> Publishing is always an explicit call: `POST /articles` only creates drafts. Pipeline runs and paid scans cost credits and respect the Site's spend cap.

## Moving a blog in

- `import_content` imports a whole blog after a dry run, keeping slugs, publish dates and drafts and copying images into the media library. The `migrate-content` prompt guides it; export recipes are in [Move a blog to Writavo](/docs/migrate).
- Send the import document with the one-time `curl` upload command it returns, as an https `url`, or inline in parts (at most 50 articles and 512 KB each), then continue with the `import_id`. It is stored on the server (up to 10 MB, kept 7 days after last use) for the Site, so signing in again keeps it; with a key made by hand it belongs to that key.
- An apply runs in the background, so nothing has to stay connected; `status: true` checks on it.
- `upload_media` takes an image by https URL or as base64.
- `start_plan_purchase` returns the dashboard link for choosing a plan. Payment happens on Stripe's page, never in the chat. A plan is only needed for AI generation.

## Every tool

Generated from `openapi.yaml`, with the API's scopes and gates. Asks first: the tool asks for `confirm: true`. Approval: a person also approves it in the dashboard while the organisation requires it.

| Tool | Calls | Scope | Asks first | Approval |
|---|---|---|---|---|
| verify_api_key | GET /ping | none |  |  |
| get_site_info | GET /site | meta:read |  |  |
| get_usage | GET /usage | meta:read |  |  |
| list_articles | GET /articles | articles:read |  |  |
| create_article | POST /articles | articles:write |  |  |
| get_article | GET /articles/{id} | articles:read |  |  |
| update_article | PATCH /articles/{id} | articles:write |  |  |
| delete_article | DELETE /articles/{id} | articles:write | yes | yes |
| publish_article | POST /articles/{id}/publish | articles:write | yes |  |
| unpublish_article | POST /articles/{id}/unpublish | articles:write | yes | yes |
| schedule_article | POST /articles/{id}/schedule | articles:write | yes |  |
| cancel_article_schedule | POST /articles/{id}/cancel-schedule | articles:write |  |  |
| list_categories | GET /categories | taxonomy:read |  |  |
| create_category | POST /categories | taxonomy:write |  |  |
| get_category | GET /categories/{id} | taxonomy:read |  |  |
| update_category | PATCH /categories/{id} | taxonomy:write |  |  |
| delete_category | DELETE /categories/{id} | taxonomy:write | yes | yes |
| list_tags | GET /tags | taxonomy:read |  |  |
| create_tag | POST /tags | taxonomy:write |  |  |
| get_tag | GET /tags/{id} | taxonomy:read |  |  |
| update_tag | PATCH /tags/{id} | taxonomy:write |  |  |
| delete_tag | DELETE /tags/{id} | taxonomy:write | yes | yes |
| list_authors | GET /authors | authors:read |  |  |
| create_author | POST /authors | authors:write |  |  |
| get_author | GET /authors/{id} | authors:read |  |  |
| update_author | PATCH /authors/{id} | authors:write |  |  |
| delete_author | DELETE /authors/{id} | authors:write | yes | yes |
| list_media | GET /media | media:read |  |  |
| get_media | GET /media/{id} | media:read |  |  |
| update_media | PATCH /media/{id} | media:write |  |  |
| delete_media | DELETE /media/{id} | media:write | yes | yes |
| list_pipeline_runs | GET /pipeline/runs | pipeline:read |  |  |
| trigger_pipeline_run | POST /pipeline/runs | pipeline:run | yes | yes |
| get_pipeline_status | GET /pipeline/runs/{id} | pipeline:read |  |  |
| get_pipeline_queue | GET /pipeline/queue | pipeline:read |  |  |
| get_content_types | GET /content-types | entries:read |  |  |
| get_content_type | GET /content-types/{api_id} | entries:read |  |  |
| list_entries | GET /entries/{type} | entries:read |  |  |
| create_entry | POST /entries/{type} | entries:write |  |  |
| get_entry | GET /entries/{type}/{id} | entries:read |  |  |
| update_entry | PATCH /entries/{type}/{id} | entries:write |  |  |
| delete_entry | DELETE /entries/{type}/{id} | entries:write | yes |  |
| publish_entry | POST /entries/{type}/{id}/publish | entries:write | yes |  |
| unpublish_entry | POST /entries/{type}/{id}/unpublish | entries:write |  |  |
| schedule_entry | POST /entries/{type}/{id}/schedule | entries:write |  |  |
| upload_media | Upload an image and register it in the media library, in one call. | media:write |  |  |
| get_api_docs | Read the API reference offline. One of the few tools that needs no key. | none |  |  |
| start_plan_purchase | Get the dashboard link to choose a plan. Payment happens on Stripe's page, never in the chat. | none |  |  |
| import_content | Import articles from a Writavo import file: dry run first, then create, re-host images and publish with original dates. | articles:write | yes |  |
| wait_for_approval | Wait for a person to approve or deny an action that needs approval; returns as soon as they decide. Never approves anything itself. | meta:read |  |  |
| list_sites | List the Sites this connection can work on and which is the default. Every other tool takes an optional site to pick one. | meta:read |  |  |
| search_writavo_actions | Find the operation for a settings, delivery, SEO, analytics, comments, team, billing or insights task, with its input schema and whether it needs approval or costs money. | none |  |  |
| read_writavo_action | Run one READ operation found with search_writavo_actions (settings, SEO, analytics, comments, team, billing, insights). Changes nothing. | per action |  |  |
| run_writavo_action | Run one operation that CHANGES something, found with search_writavo_actions, validated against its schema, with the same confirmation and approval steps as every other tool. | per action | yes |  |

## Every action

Reached through `read_writavo_action` (GETs) and `run_writavo_action` (everything else); pass the name or operationId. Approval: every time, or only while the organisation requires approvals.

| Area | Action | Calls | Scope | Approval | Costs |
|---|---|---|---|---|---|
| Analytics | check_analytics_install | POST /analytics/install-check | insights:read |  |  |
| Analytics | get_analytics_setup | GET /analytics/setup | insights:read |  |  |
| Analytics | get_visitor_analytics | GET /analytics/visitors | insights:read |  |  |
| Analytics | update_analytics_settings | PATCH /analytics/settings | site:write |  |  |
| Articles | bulk_delete_articles | POST /articles/bulk-delete | articles:write | while approvals are on |  |
| Articles | cancel_article_unpublish | POST /articles/{id}/cancel-unpublish | articles:write |  |  |
| Articles | create_article_preview_link | POST /articles/{id}/preview-links | articles:write |  |  |
| Articles | get_article_revision | GET /articles/{id}/revisions/{revision_id} | articles:read |  |  |
| Articles | list_article_preview_links | GET /articles/{id}/preview-links | articles:read |  |  |
| Articles | list_article_revisions | GET /articles/{id}/revisions | articles:read |  |  |
| Articles | restore_article_revision | POST /articles/{id}/revisions/{revision_id}/restore | articles:write |  |  |
| Articles | revoke_article_preview_link | DELETE /articles/{id}/preview-links/{link_id} | articles:write |  |  |
| Articles | schedule_article_unpublish | POST /articles/{id}/schedule-unpublish | articles:write | while approvals are on |  |
| Articles | set_article_cost_history | POST /articles/{id}/cost-history | articles:write |  |  |
| Articles | set_article_cost_history_bulk | POST /articles/cost-history | articles:write |  |  |
| Articles | set_article_link_rel | POST /articles/{id}/link-rel | articles:write |  |  |
| Authors | bulk_delete_authors | POST /authors/bulk-delete | authors:write | while approvals are on |  |
| Billing | buy_credit_pack_with_balance | POST /billing/credit-packs/{key}/buy-with-balance | billing:write | always | money |
| Billing | get_billing_links | GET /billing/links | billing:read |  |  |
| Billing | get_billing_summary | GET /billing | billing:read |  |  |
| Billing | keep_current_plan | POST /billing/scheduled-change/cancel | billing:write | always | money |
| Billing | list_billing_activity | GET /billing/activity | billing:read |  |  |
| Billing | list_credit_packs | GET /billing/credit-packs | billing:read |  |  |
| Billing | list_invoices | GET /billing/invoices | billing:read |  |  |
| Billing | start_credit_purchase | POST /billing/credit-packs/{key}/checkout | billing:write |  |  |
| Billing | start_wallet_topup | POST /billing/wallet/checkout | billing:write |  |  |
| Billing | update_autorefill | PATCH /billing/autorefill | billing:write | always | money |
| Billing | update_site_credit_cap | PATCH /billing/site-credit-cap | billing:write | always |  |
| Categories | bulk_delete_categories | POST /categories/bulk-delete | taxonomy:write | while approvals are on |  |
| Comments | delete_comment | DELETE /comments/{id} | comments:write |  |  |
| Comments | erase_commenter | POST /comments/erase | comments:write |  |  |
| Comments | get_comment | GET /comments/{id} | comments:read |  |  |
| Comments | get_comment_settings | GET /comments/settings | comments:read |  |  |
| Comments | get_post_comments | GET /comments/posts/{slug} | articles:read |  |  |
| Comments | import_comments | POST /comments/import | comments:write |  |  |
| Comments | list_comments | GET /comments | comments:read |  |  |
| Comments | reply_to_comment | POST /comments/{id}/replies | comments:write |  |  |
| Comments | submit_comment | POST /comments | engagement:write |  |  |
| Comments | update_comment | PATCH /comments/{id} | comments:write |  |  |
| Comments | update_comment_settings | PATCH /comments/settings | comments:write |  |  |
| Content types | apply_content_schema | POST /content-types/apply | content_types:write |  |  |
| Content types | create_content_type | POST /content-types | content_types:write |  |  |
| Content types | delete_content_type | DELETE /content-types/{api_id} | content_types:write |  |  |
| Content types | get_content_types_typescript | GET /content-types/typescript | entries:read |  |  |
| Content types | update_content_type | PATCH /content-types/{api_id} | content_types:write |  |  |
| Delivery | connect_cms | POST /delivery/cms | integrations:write |  |  |
| Delivery | connect_custom_domain | POST /delivery/custom-domain | delivery:write | always | money |
| Delivery | disconnect_cms | DELETE /delivery/cms/{provider} | integrations:write | always |  |
| Delivery | get_delivery | GET /delivery | delivery:read |  |  |
| Delivery | get_hosted_site | GET /delivery/hosted-site | delivery:read |  |  |
| Delivery | get_proxy_installers | GET /delivery/proxy/installers | delivery:read |  |  |
| Delivery | list_cms_connections | GET /delivery/cms | delivery:read |  |  |
| Delivery | list_cms_push_log | GET /delivery/cms/push-log | delivery:read |  |  |
| Delivery | publish_hosted_site | POST /delivery/hosted-site/publish | delivery:write | always |  |
| Delivery | push_to_cms | POST /delivery/cms/push | integrations:write | always |  |
| Delivery | remove_custom_domain | DELETE /delivery/custom-domain | delivery:write | always |  |
| Delivery | run_delivery_health_check | POST /delivery/health-checks | delivery:write |  |  |
| Delivery | setup_headless_delivery | POST /delivery/headless | delivery:write |  |  |
| Delivery | setup_reverse_proxy | POST /delivery/proxy | delivery:write | always |  |
| Delivery | update_hosted_site_branding | PATCH /delivery/hosted-site/branding | site:write |  |  |
| Device sign-in | revoke_oauth_key | POST /auth/key/revoke-oauth | none |  |  |
| Engagement | get_post_engagement | GET /engagement/posts/{slug} | articles:read |  |  |
| Engagement | import_engagement | POST /engagement/import | engagement:write |  |  |
| Engagement | list_posts_engagement | GET /engagement/posts | articles:read |  |  |
| Engagement | record_engagement | POST /engagement/events | engagement:write |  |  |
| Entries | get_entry_revision | GET /entries/{type}/{id}/revisions/{rid} | entries:read |  |  |
| Entries | list_entry_revisions | GET /entries/{type}/{id}/revisions | entries:read |  |  |
| Entries | restore_entry_revision | POST /entries/{type}/{id}/revisions/{rid}/restore | entries:write |  |  |
| Entries | schedule_entry_unpublish | POST /entries/{type}/{id}/schedule-unpublish | entries:write |  |  |
| Entries | unschedule_entry | POST /entries/{type}/{id}/unschedule | entries:write |  |  |
| Formats and prompts | create_format | POST /formats | prompts:write |  |  |
| Formats and prompts | delete_format | DELETE /formats/{id} | prompts:write | always |  |
| Formats and prompts | get_format | GET /formats/{id} | meta:read |  |  |
| Formats and prompts | list_prompts | GET /pipeline/prompts | pipeline:read |  |  |
| Formats and prompts | reset_prompt | DELETE /pipeline/prompts/{stage} | prompts:write |  |  |
| Formats and prompts | set_prompt_override | PATCH /pipeline/prompts/{stage} | prompts:write |  |  |
| Formats and prompts | update_format | PATCH /formats/{id} | prompts:write |  |  |
| Insights | get_article_costs | GET /insights/articles/{id}/costs | insights:read |  |  |
| Insights | get_site_costs | GET /insights/costs | insights:read |  |  |
| Insights | get_site_overview | GET /insights/overview | insights:read |  |  |
| Insights | get_taxonomy_counts | GET /insights/taxonomy | insights:read |  |  |
| Insights | list_agent_calls | GET /logs/agent-calls | logs:read |  |  |
| Insights | list_audit_log | GET /logs/audit | logs:read |  |  |
| Insights | list_function_logs | GET /logs/functions | logs:read |  |  |
| Media | bulk_delete_media | POST /media/bulk-delete | media:write | while approvals are on |  |
| Meta | get_approval_status | GET /approvals/{id} | meta:read |  |  |
| Meta | list_formats | GET /formats | meta:read |  |  |
| Organisation | get_organisation | GET /organisation | meta:read |  |  |
| Organisation | rename_organisation | PATCH /organisation | org:write |  |  |
| Outreach | get_outreach_mailbox | GET /outreach/mailbox | outreach:read |  |  |
| Outreach | get_outreach_readiness | GET /outreach/readiness | outreach:read |  |  |
| Outreach | list_outreach_campaigns | GET /outreach/campaigns | outreach:read |  |  |
| Outreach | list_outreach_contacts | GET /outreach/contacts | outreach:read |  |  |
| Outreach | list_outreach_threads | GET /outreach/threads | outreach:read |  |  |
| Pipeline | activate_recipe_draft | POST /pipeline/recipe/draft/activate | pipeline:config | always | credits |
| Pipeline | create_plan_item | POST /pipeline/queue | plan:write |  |  |
| Pipeline | delete_plan_item | DELETE /pipeline/queue/{id} | plan:write |  |  |
| Pipeline | discard_recipe_draft | DELETE /pipeline/recipe/draft | pipeline:config |  |  |
| Pipeline | estimate_recipe | POST /pipeline/recipe/estimate | pipeline:read |  |  |
| Pipeline | explain_recipe | GET /pipeline/recipe/explain | pipeline:read |  |  |
| Pipeline | get_pipeline_config | GET /pipeline/config | pipeline:read |  |  |
| Pipeline | get_pipeline_source | GET /pipeline/sources/{id} | pipeline:read |  |  |
| Pipeline | get_plan_item | GET /pipeline/queue/{id} | pipeline:read |  |  |
| Pipeline | get_recipe | GET /pipeline/recipe | pipeline:read |  |  |
| Pipeline | list_pipeline_sources | GET /pipeline/sources | pipeline:read |  |  |
| Pipeline | list_recipe_activity | GET /pipeline/recipe/activity | pipeline:read |  |  |
| Pipeline | list_recipe_steps | GET /pipeline/steps | pipeline:read |  |  |
| Pipeline | list_recipe_templates | GET /pipeline/templates | pipeline:read |  |  |
| Pipeline | reorder_plan_items | POST /pipeline/queue/reorder | plan:write |  |  |
| Pipeline | requeue_article | POST /pipeline/articles/{id}/requeue | pipeline:run | always | credits |
| Pipeline | save_recipe_draft | POST /pipeline/recipe/draft | pipeline:config |  |  |
| Pipeline | test_recipe_draft | POST /pipeline/recipe/draft/test | pipeline:run | always | credits |
| Pipeline | undo_recipe | POST /pipeline/recipe/undo | pipeline:config | always | credits |
| Pipeline | update_pipeline_config | PATCH /pipeline/config | pipeline:config | always | credits |
| Pipeline | update_plan_item | PATCH /pipeline/queue/{id} | plan:write |  |  |
| Redirects | bulk_redirects | POST /redirects/bulk | articles:write |  |  |
| Redirects | create_redirect | POST /redirects | articles:write |  |  |
| Redirects | delete_redirect | DELETE /redirects/{id} | articles:write |  |  |
| Redirects | export_redirects | GET /redirects/export | articles:read |  |  |
| Redirects | get_redirect | GET /redirects/{id} | articles:read |  |  |
| Redirects | list_redirects | GET /redirects | articles:read |  |  |
| Redirects | update_redirect | PATCH /redirects/{id} | articles:write |  |  |
| SEO | acknowledge_keyword_alerts | POST /seo/keyword-alerts/acknowledge | seo:write |  |  |
| SEO | add_competitor | POST /seo/competitors | seo:write |  |  |
| SEO | add_disavow_entry | POST /seo/backlinks/disavow | seo:write |  |  |
| SEO | add_link_opportunity | POST /seo/link-opportunities | seo:write |  |  |
| SEO | check_link_exchange | POST /seo/link-exchanges/{id}/check | seo:write |  |  |
| SEO | check_link_exchanges | POST /seo/link-exchanges/check | seo:write |  |  |
| SEO | check_llm_mentions | POST /seo/llm-mentions/check | seo:write | always | credits |
| SEO | connect_bing | POST /seo/backlinks/bing | integrations:write |  |  |
| SEO | create_link_exchange | POST /seo/link-exchanges | seo:write |  |  |
| SEO | get_ai_visibility | GET /seo/ai-visibility | seo:read |  |  |
| SEO | get_backlink_overview | GET /seo/backlinks/overview | seo:read |  |  |
| SEO | get_disavow_file | GET /seo/backlinks/disavow-file | seo:read |  |  |
| SEO | get_engagement | GET /seo/engagement | seo:read |  |  |
| SEO | get_internal_link_health | GET /seo/internal-links | seo:read |  |  |
| SEO | get_internal_link_report | GET /seo/internal-links/health | seo:read |  |  |
| SEO | get_keyword_history | GET /seo/keywords/{id}/history | seo:read |  |  |
| SEO | get_link_exchange | GET /seo/link-exchanges/{id} | seo:read |  |  |
| SEO | get_seo_overview | GET /seo/overview | seo:read |  |  |
| SEO | import_backlinks_csv | POST /seo/backlinks/import | seo:write |  |  |
| SEO | import_seo | POST /seo/import | seo:write |  |  |
| SEO | inspect_link_prospect | POST /seo/link-prospects/inspect | seo:write |  |  |
| SEO | list_article_links | GET /seo/links | seo:read |  |  |
| SEO | list_backlinks | GET /seo/backlinks | seo:read |  |  |
| SEO | list_competitors | GET /seo/competitors | seo:read |  |  |
| SEO | list_content_gaps | GET /seo/content-gaps | seo:read |  |  |
| SEO | list_disavow_entries | GET /seo/backlinks/disavow | seo:read |  |  |
| SEO | list_keyword_alerts | GET /seo/keyword-alerts | seo:read |  |  |
| SEO | list_link_exchanges | GET /seo/link-exchanges | seo:read |  |  |
| SEO | list_link_opportunities | GET /seo/link-opportunities | seo:read |  |  |
| SEO | list_llm_mentions | GET /seo/llm-mentions | seo:read |  |  |
| SEO | list_outbound_link_domains | GET /seo/outbound-links | seo:read |  |  |
| SEO | list_outbound_links | GET /seo/outbound-links/links | seo:read |  |  |
| SEO | list_tracked_keywords | GET /seo/keywords | seo:read |  |  |
| SEO | plan_content_gap | POST /seo/content-gaps/{id}/plan | seo:write + plan:write |  |  |
| SEO | plan_link_opportunity | POST /seo/link-opportunities/{id}/plan | seo:write + plan:write |  |  |
| SEO | pull_backlink_detail | POST /seo/backlinks/detail-pull | seo:write | always | credits |
| SEO | refresh_site_metrics | POST /seo/site-metrics/refresh | seo:write | always | credits |
| SEO | remove_competitor | DELETE /seo/competitors/{id} | seo:write |  |  |
| SEO | remove_disavow_entry | DELETE /seo/backlinks/disavow/{id} | seo:write |  |  |
| SEO | remove_link_exchange | DELETE /seo/link-exchanges/{id} | seo:write |  |  |
| SEO | rescan_internal_links | POST /seo/internal-links/rescan | seo:write |  |  |
| SEO | run_ai_visibility | POST /seo/ai-visibility/run | seo:write | always | credits |
| SEO | run_rank_check | POST /seo/rank-check | seo:write | always | money |
| SEO | scan_backlink_profile | POST /seo/backlinks/scan | seo:write | always | credits |
| SEO | scan_content_gaps | POST /seo/content-gaps/scan | seo:write | always | credits |
| SEO | scan_link_intersect | POST /seo/link-opportunities/intersect-scan | seo:write | always | credits |
| SEO | sync_bing | POST /seo/backlinks/bing/sync | seo:write |  |  |
| SEO | track_keyword | POST /seo/keywords | seo:write |  |  |
| SEO | untrack_keyword | DELETE /seo/keywords/{id} | seo:write |  |  |
| SEO | update_competitor | PATCH /seo/competitors/{id} | seo:write |  |  |
| SEO | update_content_gap | PATCH /seo/content-gaps/{id} | seo:write |  |  |
| SEO | update_link_exchange | PATCH /seo/link-exchanges/{id} | seo:write |  |  |
| SEO | update_link_opportunity | PATCH /seo/link-opportunities/{id} | seo:write |  |  |
| SEO | update_tracked_keyword | PATCH /seo/keywords/{id} | seo:write |  |  |
| SEO | verify_backlinks | POST /seo/backlinks/verify | seo:write |  |  |
| Site settings | get_knowledge_profile | GET /site/knowledge-profile | site:read |  |  |
| Site settings | get_site_settings | GET /site/settings | site:read |  |  |
| Site settings | update_knowledge_profile | PATCH /site/knowledge-profile | site:write |  |  |
| Site settings | update_site_settings | PATCH /site/settings | site:write |  |  |
| Tags | bulk_delete_tags | POST /tags/bulk-delete | taxonomy:write | while approvals are on |  |
| Team | get_member_permissions | GET /team/members/{user_id}/permissions | team:read |  |  |
| Team | get_role_matrix | GET /team/roles | team:read |  |  |
| Team | get_team_member | GET /team/members/{user_id} | team:read |  |  |
| Team | invite_team_member | POST /team/invites | team:write | always |  |
| Team | list_permission_catalog | GET /team/permissions | team:read |  |  |
| Team | list_team_invites | GET /team/invites | team:read |  |  |
| Team | list_team_members | GET /team/members | team:read |  |  |
| Team | remove_team_member | DELETE /team/members/{user_id} | team:write | always |  |
| Team | revoke_team_invite | DELETE /team/invites/{id} | team:write |  |  |
| Team | update_member_permissions | PATCH /team/members/{user_id}/permissions | roles:write | always |  |
| Team | update_member_role | PATCH /team/members/{user_id} | team:write | always |  |
| Team | update_role_permissions | PATCH /team/roles/{role} | roles:write | always |  |

## What it deliberately cannot do

Whatever it is granted, an assistant can never do these, and the server refuses them too. Below the table: the two parts of the API it cannot reach at all.

| Never | Why | Next step |
|---|---|---|
| Change the AI agent switch, the approvals switch or the default permissions | An agent must not be able to switch off the controls that govern it. | A person changes this at https://app.writavo.com/settings/agents. |
| Approve its own requests, or widen its own access | An approval is a person saying yes; an agent approving itself is no approval at all. | The person approves at the link, or reconnects the assistant to choose more permissions. |
| Change the access of the person it acts for (their role, their permissions, their role's permissions) | That would be an agent widening its own access by another route. | That person, or another owner or admin, does it at https://app.writavo.com/team. |
| Delete a Site or the organisation | Irreversible, and it takes a live blog down for everyone. | Not available to AI agents. The person contacts https://writavo.com/support. |
| Enter or change payment details | Card details never pass through an AI assistant. | Add or change a card at https://app.writavo.com/billing?action=add-card. |
| Change the plan | A plan change is a purchase the person makes on Stripe's page. | Get the plan link with start_plan_purchase (or https://app.writavo.com/billing) and give it to the person. |
| Transfer ownership or make anyone an owner | Ownership is the last word on an organisation and changes hands only in person. | The owner does it at https://app.writavo.com/team. |
| Accept the outreach policy, pass identity checks, or connect an outreach mailbox | Sending outreach is a legal commitment, and a mailbox password never passes through an AI assistant. | An owner or a person with integrations access does it at https://app.writavo.com/outreach. |
| Enter a CMS or Bing Webmaster Tools credential | Third party credentials never pass through an AI assistant. | The connect actions return the dashboard page where the person pastes it (https://app.writavo.com/delivery). |
| Create, rotate or revoke API keys; manage webhooks | A tool that can mint a credential is a tool whose compromise mints credentials. | A person does this at https://app.writavo.com/settings/api-keys or https://app.writavo.com/settings/webhooks. |
| Anything that needs Writavo platform staff | Platform administration is not something an organisation or its agents can reach. | Not something an organisation can change. The person contacts https://writavo.com/support. |
