{
  "openapi": "3.1.0",
  "info": {
    "title": "Rankwise API",
    "version": "2026-07-07",
    "summary": "Measure whether AI engines cite a brand, and win the citations back.",
    "description": "Two surfaces, one document.\n\n**`/api/v1/*` is the REST API.** Authenticate with a workspace API key as a bearer token. It is a Growth-plan feature. It covers visibility (citations, share of voice, dimensions, events), the site and its automatic articles, planner keywords, articles, the Content Planner, Search Console and usage.\n\nEvery key reads. A key created with \"Allow changes\" also gets the write scopes (`sites:write`, `keywords:write`, `articles:write`, `planner:write`): pause and resume, add keywords, move planner cards and replace articles. None of them spends credits. The one call that spends is `POST /api/v1/audits`, which needs the `audit:run` scope.\n\nLimits: 120 requests a minute and 10,000 a UTC day per key, reported on every response in `RateLimit` and `RateLimit-Policy` headers.\n\n**`/api/mcp` is the agent API.** It speaks MCP over JSON-RPC on a single POST path, and it is the surface to use when an agent must act, not only read. 43 workspace tools live behind OAuth 2.1 or an API key, grouped in toolsets that the plan and the key's scopes switch on, and a smaller set of public tools needs no sign-in at all. Add `?toolsets=planner,articles` to list only some groups.\n\nThe tools are published under `x-mcp-tools` on the `/api/mcp` path, with the OAuth scope each one needs. They are deliberately not described as REST paths, because they are not REST paths and calling them as such returns 404.\n\nScopes: `read` never changes or spends. `write` changes the workspace. `spend` consumes plan credits. Check the scope before you call, and read https://tryrankwise.com/api-docs for the prose.",
    "contact": {
      "name": "Rankwise",
      "url": "https://tryrankwise.com/contact"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://tryrankwise.com/terms"
    },
    "termsOfService": "https://tryrankwise.com/terms"
  },
  "servers": [
    {
      "url": "https://tryrankwise.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Visibility (read-only REST)",
      "description": "Keyed GET endpoints for citations, share of voice, dimension scores and events."
    },
    {
      "name": "Audits (spend, opt-in scope)",
      "description": "The one call an API key can make that spends: a fresh audit. Needs the `audit:run` scope."
    },
    {
      "name": "Sites",
      "description": "Keyed /api/v1 endpoints for sites. Each names the key scope it needs."
    },
    {
      "name": "Keywords",
      "description": "Keyed /api/v1 endpoints for keywords. Each names the key scope it needs."
    },
    {
      "name": "Articles",
      "description": "Keyed /api/v1 endpoints for articles. Each names the key scope it needs."
    },
    {
      "name": "Content Planner",
      "description": "Keyed /api/v1 endpoints for content planner. Each names the key scope it needs."
    },
    {
      "name": "Search Console",
      "description": "Keyed /api/v1 endpoints for search console. Each names the key scope it needs."
    },
    {
      "name": "Usage",
      "description": "Keyed /api/v1 endpoints for usage. Each names the key scope it needs."
    },
    {
      "name": "Discovery",
      "description": "Unauthenticated endpoints that describe the rest."
    },
    {
      "name": "Agent API (MCP)",
      "description": "The JSON-RPC endpoint and its 43 workspace tools, each with the scope it needs."
    }
  ],
  "paths": {
    "/api/v1": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "Discovery index",
        "description": "A self-describing catalogue of endpoints and a pointer to the MCP endpoint. Needs no key, so it also answers 'is this API live'.",
        "tags": [
          "Discovery"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The catalogue.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/citations": {
      "get": {
        "operationId": "getCitations",
        "summary": "Citations per query and engine",
        "description": "For each tracked query, whether each engine cited the domain, at what position, and which URLs it cited.",
        "tags": [
          "Visibility (read-only REST)"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "A domain the key's workspace tracks. A bare hostname is expected; a scheme, `www.` and any path are normalized off.",
            "schema": {
              "type": "string",
              "examples": [
                "example.com"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Citations per query and engine",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Citations"
                }
              }
            }
          },
          "400": {
            "description": "`missing_domain`, or a malformed parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`domain_not_found`. The workspace does not track that domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/share-of-voice": {
      "get": {
        "operationId": "getShareOfVoice",
        "summary": "AI share-of-voice leaderboard",
        "description": "The latest measured share-of-voice snapshot, own domain against competitors. When `measured` is false no snapshot exists yet, and the numbers are absent rather than zero.",
        "tags": [
          "Visibility (read-only REST)"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "A domain the key's workspace tracks. A bare hostname is expected; a scheme, `www.` and any path are normalized off.",
            "schema": {
              "type": "string",
              "examples": [
                "example.com"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "AI share-of-voice leaderboard",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ShareOfVoice"
                }
              }
            }
          },
          "400": {
            "description": "`missing_domain`, or a malformed parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`domain_not_found`. The workspace does not track that domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/dimensions": {
      "get": {
        "operationId": "getDimensions",
        "summary": "Per-dimension visibility scores",
        "description": "The latest score and confidence for each on-page AI-visibility dimension, with the recommendations attached to it.",
        "tags": [
          "Visibility (read-only REST)"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "A domain the key's workspace tracks. A bare hostname is expected; a scheme, `www.` and any path are normalized off.",
            "schema": {
              "type": "string",
              "examples": [
                "example.com"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Per-dimension visibility scores",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dimensions"
                }
              }
            }
          },
          "400": {
            "description": "`missing_domain`, or a malformed parameter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`domain_not_found`. The workspace does not track that domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/events": {
      "get": {
        "operationId": "listVisibilityEvents",
        "summary": "Visibility events",
        "description": "Events for the key's workspace, newest first: citations won and lost, fixes proposed, goals reached. Poll with `since` set to the newest `createdAt` you already hold.",
        "tags": [
          "Visibility (read-only REST)"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "ISO-8601 lower bound, exclusive.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Defaults to 50, capped at 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The events page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Events"
                }
              }
            }
          },
          "400": {
            "description": "A malformed `since` or `limit`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/key": {
      "get": {
        "operationId": "getApiKey",
        "summary": "The calling key's scopes",
        "description": "Which scopes this key carries and, for a key with `audit:run`, the credit cost of one audit, the daily cap and how much of it is used. Never changes or spends anything.",
        "tags": [
          "Visibility (read-only REST)"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "The key's scopes and audit allowance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyInfo"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/audits": {
      "post": {
        "operationId": "startAudit",
        "summary": "Start a fresh audit of a tracked domain",
        "description": "Re-crawls and re-scores one domain the workspace already tracks, the same work as \"Crawl now\" in the dashboard. Costs 1 plan credit.\n\n**Requires the `audit:run` scope.** A key gets it only if the box was ticked when the key was created. A read-only key gets 403 `insufficient_scope`. This is the only call an API key can make that spends.\n\n**Send an `Idempotency-Key` header**, unique per audit, and the same one on a retry. A retry of a charged key returns the original response with `replayed: true` and never charges twice. The same key with a different domain is refused with 409.\n\nEach key has a daily cap (default 50, at most 500, set at creation) that resets at 00:00 UTC. Send `X-Rankwise-Source` to name your integration; it is recorded on every charge.",
        "tags": [
          "Audits (spend, opt-in scope)"
        ],
        "security": [
          {
            "apiKey": [
              "audit:run"
            ]
          }
        ],
        "x-rankwise-scope": "audit:run",
        "x-rankwise-credits": 1,
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "8 to 128 letters, digits, `.`, `_`, `:` or `-`. Unique per audit; reuse it on a retry.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]{8,128}$"
            }
          },
          {
            "name": "X-Rankwise-Source",
            "in": "header",
            "required": false,
            "description": "A fixed id for your integration, e.g. `google-sheets-addon`. Recorded on the charge.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "A domain the key's workspace tracks. A scheme, `www.` and any path are normalized off.",
                    "examples": [
                      "example.com"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The audit is queued and charged (or replayed).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Audit"
                }
              }
            }
          },
          "400": {
            "description": "`missing_idempotency_key`, or `missing_domain` when the body has no domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required` (plan below Growth) or `out_of_credits`. Both carry nothing charged; `out_of_credits` adds `upgrade_url`, `credits_required` and `credits_remaining`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key was created without `audit:run`. Create a new key with the box ticked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`domain_not_found`. The workspace does not track that domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`idempotency_key_reused`. The Idempotency-Key was used for a different domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`daily_cap_reached` (adds `daily_cap` and `audits_today`), or `rate_limited`. Nothing was charged.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "`audit_not_started`. The audit could not be queued and its credits were refunded. Retry with the same Idempotency-Key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "`audits_paused`. Our spend breaker is open. Nothing was charged; honour `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sites": {
      "get": {
        "operationId": "listSites",
        "summary": "List sites",
        "description": "The site this key reaches (a key belongs to one workspace): its id, name, tracked domains, and whether automatic articles are on and paused.",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "apiKey": [
              "sites:read"
            ]
          }
        ],
        "x-rankwise-scope": "sites:read",
        "x-rankwise-tool": "list_sites",
        "parameters": [],
        "responses": {
          "200": {
            "description": "List sites",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sites": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The site id. It is the workspace id."
                          },
                          "name": {
                            "type": "string"
                          },
                          "domains": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "domain": {
                                  "type": "string"
                                }
                              },
                              "required": [],
                              "additionalProperties": true
                            }
                          },
                          "automatic_articles": {
                            "type": "object",
                            "properties": {
                              "mode": {
                                "type": "string"
                              },
                              "articles_per_week": {
                                "type": "integer"
                              },
                              "paused": {
                                "type": "boolean"
                              },
                              "paused_reason": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              }
                            },
                            "required": [],
                            "additionalProperties": true
                          },
                          "planner_url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "domains",
                          "automatic_articles"
                        ],
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "sites"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `sites:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sites/{site_id}/pause": {
      "post": {
        "operationId": "pauseSite",
        "summary": "Pause automatic articles",
        "description": "Pause automatic articles. While paused nothing runs on its own and no credits are used. Free and idempotent.",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "apiKey": [
              "sites:write"
            ]
          }
        ],
        "x-rankwise-scope": "sites:write",
        "x-rankwise-tool": "pause_site",
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "description": "The site id from GET /api/v1/sites.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pause automatic articles",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "site": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The site id. It is the workspace id."
                        },
                        "name": {
                          "type": "string"
                        },
                        "domains": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "domain": {
                                "type": "string"
                              }
                            },
                            "required": [],
                            "additionalProperties": true
                          }
                        },
                        "automatic_articles": {
                          "type": "object",
                          "properties": {
                            "mode": {
                              "type": "string"
                            },
                            "articles_per_week": {
                              "type": "integer"
                            },
                            "paused": {
                              "type": "boolean"
                            },
                            "paused_reason": {
                              "type": [
                                "string",
                                "null"
                              ]
                            }
                          },
                          "required": [],
                          "additionalProperties": true
                        },
                        "planner_url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "domains",
                        "automatic_articles"
                      ],
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "site"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `sites:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sites/{site_id}/resume": {
      "post": {
        "operationId": "resumeSite",
        "summary": "Resume automatic articles",
        "description": "Resume automatic articles. Cards left on days that passed move to the next free publishing days. Free and idempotent.",
        "tags": [
          "Sites"
        ],
        "security": [
          {
            "apiKey": [
              "sites:write"
            ]
          }
        ],
        "x-rankwise-scope": "sites:write",
        "x-rankwise-tool": "resume_site",
        "parameters": [
          {
            "name": "site_id",
            "in": "path",
            "required": true,
            "description": "The site id from GET /api/v1/sites.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Resume automatic articles",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "site": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The site id. It is the workspace id."
                        },
                        "name": {
                          "type": "string"
                        },
                        "domains": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "domain": {
                                "type": "string"
                              }
                            },
                            "required": [],
                            "additionalProperties": true
                          }
                        },
                        "automatic_articles": {
                          "type": "object",
                          "properties": {
                            "mode": {
                              "type": "string"
                            },
                            "articles_per_week": {
                              "type": "integer"
                            },
                            "paused": {
                              "type": "boolean"
                            },
                            "paused_reason": {
                              "type": [
                                "string",
                                "null"
                              ]
                            }
                          },
                          "required": [],
                          "additionalProperties": true
                        },
                        "planner_url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "domains",
                        "automatic_articles"
                      ],
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "site"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `sites:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/keywords": {
      "get": {
        "operationId": "listKeywords",
        "summary": "List keywords",
        "description": "The keywords in the Content Planner, one per card, with title, day, state, volume and difficulty. Send `?format=csv` (or `Accept: text/csv`) for a CSV export.",
        "tags": [
          "Keywords"
        ],
        "security": [
          {
            "apiKey": [
              "keywords:read"
            ]
          }
        ],
        "x-rankwise-scope": "keywords:read",
        "x-rankwise-tool": "list_keywords",
        "parameters": [
          {
            "name": "state",
            "in": "query",
            "required": false,
            "description": "planned, writing, review, published or failed",
            "schema": {
              "type": "string",
              "enum": [
                "planned",
                "writing",
                "review",
                "published",
                "failed"
              ]
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "`csv` returns text/csv instead of JSON.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List keywords",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keywords": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The card id (use it with move_planner_card)."
                          },
                          "day": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "keyword": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "article_type": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "article_length": {
                            "type": "string"
                          },
                          "volume": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "difficulty": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "published_url": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "dashboard_url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "day",
                          "title",
                          "keyword",
                          "state"
                        ],
                        "additionalProperties": true
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "keywords",
                    "total"
                  ],
                  "additionalProperties": true
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "keyword,title,day,state,article_type,volume,difficulty,published_url\r\n"
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `keywords:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "addKeywords",
        "summary": "Add keywords",
        "description": "Add up to 50 keywords to the Content Planner. Each becomes a card on its own publishing day. Keywords already planned are skipped, so a retry never adds twice. Free.",
        "tags": [
          "Keywords"
        ],
        "security": [
          {
            "apiKey": [
              "keywords:write"
            ]
          }
        ],
        "x-rankwise-scope": "keywords:write",
        "x-rankwise-tool": "add_keywords",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "keywords": {
                    "description": "Keywords as strings, or objects with keyword, day, article_type and article_length.",
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "object",
                          "properties": {
                            "keyword": {
                              "type": "string"
                            },
                            "day": {
                              "type": "string",
                              "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                            },
                            "article_type": {
                              "type": "string",
                              "enum": [
                                "how_to",
                                "explainer",
                                "comparison",
                                "reference",
                                "listicle"
                              ]
                            },
                            "article_length": {
                              "type": "string",
                              "enum": [
                                "auto",
                                "short",
                                "medium",
                                "long",
                                "comprehensive"
                              ]
                            }
                          },
                          "required": [
                            "keyword"
                          ],
                          "additionalProperties": false
                        }
                      ]
                    }
                  }
                },
                "required": [
                  "keywords"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Add keywords",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "added": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "keyword": {
                            "type": "string"
                          },
                          "card_id": {
                            "type": "string"
                          },
                          "moved_another_card": {
                            "type": "boolean"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    },
                    "skipped": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "keyword": {
                            "type": "string"
                          },
                          "reason": {
                            "type": "string"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    },
                    "failed": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "keyword": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "added",
                    "skipped",
                    "failed"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `keywords:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/articles": {
      "get": {
        "operationId": "listArticles",
        "summary": "List articles",
        "description": "Articles in the workspace, newest first, with status, publish status and published URL.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "apiKey": [
              "articles:read"
            ]
          }
        ],
        "x-rankwise-scope": "articles:read",
        "x-rankwise-tool": "list_articles",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "ready, generating, published, failed or unpublished",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "query",
            "in": "query",
            "required": false,
            "description": "Words in the title.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "1-based page.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "description": "Up to 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List articles",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "articles": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "title": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "keyword": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "status": {
                            "type": "string"
                          },
                          "publish_status": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "published_url": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "integration_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "brief_id": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "expert_review_state": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "created_at": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "url": {
                            "type": "string"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "page_size": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "articles",
                    "total"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `articles:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/articles/{article_id}": {
      "get": {
        "operationId": "getArticle",
        "summary": "Get an article",
        "description": "One article with its metadata, sources and JSON-LD. Add `?include_html=true` for the full body.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "apiKey": [
              "articles:read"
            ]
          }
        ],
        "x-rankwise-scope": "articles:read",
        "x-rankwise-tool": "get_article",
        "parameters": [
          {
            "name": "article_id",
            "in": "path",
            "required": true,
            "description": "The article id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "include_html",
            "in": "query",
            "required": false,
            "description": "`true` returns the full body as HTML.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get an article",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "article": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "title": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "keyword": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "status": {
                          "type": "string"
                        },
                        "publish_status": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "published_url": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "integration_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "brief_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "expert_review_state": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "created_at": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "url": {
                          "type": "string"
                        }
                      },
                      "required": [],
                      "additionalProperties": true
                    },
                    "meta_description": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "slug": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "html": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "body_excerpt": {
                      "type": "string"
                    },
                    "body_truncated": {
                      "type": "boolean"
                    },
                    "last_error_code": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "sources": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "title": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "url"
                        ],
                        "additionalProperties": true
                      }
                    },
                    "schema_jsonld": {}
                  },
                  "required": [
                    "article"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `articles:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "replaceArticle",
        "summary": "Replace an article",
        "description": "Replace the title, meta description, slug or full HTML body. Send only the fields to change. The body is sanitised. A published article's live post is not changed until you publish again. Free.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "apiKey": [
              "articles:write"
            ]
          }
        ],
        "x-rankwise-scope": "articles:write",
        "x-rankwise-tool": "replace_article",
        "parameters": [
          {
            "name": "article_id",
            "in": "path",
            "required": true,
            "description": "The article id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 400
                  },
                  "meta_description": {
                    "type": "string",
                    "maxLength": 600
                  },
                  "slug": {
                    "type": "string",
                    "maxLength": 400
                  },
                  "html": {
                    "description": "The full article body as HTML. It is sanitised: scripts, styles, frames, forms and event handlers are removed.",
                    "type": "string",
                    "maxLength": 200001
                  }
                },
                "required": [],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replace an article",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "article": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "changed": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "title": {
                          "type": "string"
                        },
                        "meta_description": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "slug": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "live_copy_unchanged": {
                          "type": "boolean"
                        },
                        "url": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "changed"
                      ],
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "article"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `articles:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/articles/bulk-replace": {
      "post": {
        "operationId": "bulkReplaceArticles",
        "summary": "Replace up to 50 articles",
        "description": "The same as replacing one article, for up to 50 in one call. Each article succeeds or fails on its own; the response lists both.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "apiKey": [
              "articles:write"
            ]
          }
        ],
        "x-rankwise-scope": "articles:write",
        "x-rankwise-tool": "bulk_replace_articles",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "articles": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "article_id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "title": {
                          "type": "string",
                          "maxLength": 400
                        },
                        "meta_description": {
                          "type": "string",
                          "maxLength": 600
                        },
                        "slug": {
                          "type": "string",
                          "maxLength": 400
                        },
                        "html": {
                          "description": "The full article body as HTML. It is sanitised: scripts, styles, frames, forms and event handlers are removed.",
                          "type": "string",
                          "maxLength": 200001
                        }
                      },
                      "required": [
                        "article_id"
                      ],
                      "additionalProperties": false
                    }
                  }
                },
                "required": [
                  "articles"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replace up to 50 articles",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "replaced": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "changed": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "title": {
                            "type": "string"
                          },
                          "meta_description": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "slug": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "live_copy_unchanged": {
                            "type": "boolean"
                          },
                          "url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "changed"
                        ],
                        "additionalProperties": true
                      }
                    },
                    "failed": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "article_id": {
                            "type": "string"
                          },
                          "code": {
                            "type": "string"
                          },
                          "message": {
                            "type": "string"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "replaced",
                    "failed"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `articles:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/planner": {
      "get": {
        "operationId": "getPlanner",
        "summary": "Read the Content Planner",
        "description": "Planner cards by day. Defaults to the window the planner page shows; pass `from` and `to` (at most 120 days apart).",
        "tags": [
          "Content Planner"
        ],
        "security": [
          {
            "apiKey": [
              "planner:read"
            ]
          }
        ],
        "x-rankwise-scope": "planner:read",
        "x-rankwise-tool": "get_planner",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "First day, YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Last day, YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Read the Content Planner",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    },
                    "cards": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The card id (use it with move_planner_card)."
                          },
                          "day": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "keyword": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "article_type": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "article_length": {
                            "type": "string"
                          },
                          "volume": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "difficulty": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "published_url": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "dashboard_url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "day",
                          "title",
                          "keyword",
                          "state"
                        ],
                        "additionalProperties": true
                      }
                    },
                    "unscheduled": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "The card id (use it with move_planner_card)."
                          },
                          "day": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "keyword": {
                            "type": "string"
                          },
                          "kind": {
                            "type": "string"
                          },
                          "state": {
                            "type": "string"
                          },
                          "article_type": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "article_length": {
                            "type": "string"
                          },
                          "volume": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "difficulty": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "published_url": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "dashboard_url": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "day",
                          "title",
                          "keyword",
                          "state"
                        ],
                        "additionalProperties": true
                      }
                    }
                  },
                  "required": [
                    "from",
                    "to",
                    "cards",
                    "unscheduled"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `planner:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/planner/cards/{card_id}": {
      "patch": {
        "operationId": "movePlannerCard",
        "summary": "Move a planner card",
        "description": "Move a card that is not written yet to another publishing day. An unwritten card on that day swaps with it. Free.",
        "tags": [
          "Content Planner"
        ],
        "security": [
          {
            "apiKey": [
              "planner:write"
            ]
          }
        ],
        "x-rankwise-scope": "planner:write",
        "x-rankwise-tool": "move_planner_card",
        "parameters": [
          {
            "name": "card_id",
            "in": "path",
            "required": true,
            "description": "The card id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "day": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  }
                },
                "required": [
                  "day"
                ],
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Move a planner card",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "moved": {
                      "type": "boolean"
                    },
                    "day": {
                      "type": "string"
                    },
                    "swapped_with": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "moved",
                    "day"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope` (the key lacks `planner:write`; create a key with \"Allow changes\") or `forbidden_role` (the key's creator is no longer an admin).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`not_found`. Nothing with that id in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "`conflict`, for example a planner day held by a written article.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/gsc/summary": {
      "get": {
        "operationId": "getSearchConsoleSummary",
        "summary": "Search Console summary",
        "description": "Clicks, impressions and the best articles over the last 28 days, from the synced Search Console data.",
        "tags": [
          "Search Console"
        ],
        "security": [
          {
            "apiKey": [
              "gsc:read"
            ]
          }
        ],
        "x-rankwise-scope": "gsc:read",
        "x-rankwise-tool": "get_search_console_summary",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Search Console summary",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connected": {
                      "type": "boolean"
                    },
                    "days": {
                      "type": "integer"
                    },
                    "clicks": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "impressions": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "best_articles": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string"
                          },
                          "clicks": {
                            "type": "number"
                          },
                          "impressions": {
                            "type": "number"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    },
                    "connect_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "connected",
                    "days",
                    "best_articles"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `gsc:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/usage": {
      "get": {
        "operationId": "getUsage",
        "summary": "Plan, credits, limits and this key's entitlements",
        "description": "The plan, credit balance and plan limits, plus this key's scopes, its rate-limit windows and which toolsets it may use (full, read or none).",
        "tags": [
          "Usage"
        ],
        "security": [
          {
            "apiKey": [
              "usage:read"
            ]
          }
        ],
        "x-rankwise-scope": "usage:read",
        "x-rankwise-tool": "get_plan_and_credits",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Plan, credits, limits and this key's entitlements",
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string"
                    },
                    "credits": {
                      "type": "number"
                    },
                    "agency_billing": {
                      "type": "boolean"
                    },
                    "brief_draft_cost_credits": {
                      "type": "number"
                    },
                    "can_publish_to_cms": {
                      "type": "boolean"
                    },
                    "limits": {
                      "type": "object",
                      "properties": {
                        "max_domains": {
                          "type": "number"
                        },
                        "max_questions_per_domain": {
                          "type": "number"
                        },
                        "engines": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "monthly_check_budget": {
                          "type": "number"
                        },
                        "on_demand_checks_per_month": {
                          "type": "number"
                        }
                      },
                      "required": [],
                      "additionalProperties": true
                    },
                    "current_period_end": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "trial_ends_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "billing_url": {
                      "type": "string"
                    },
                    "pricing_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "plan",
                    "credits",
                    "limits"
                  ],
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "`invalid_input` or `invalid_json`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "No key, a malformed key, or a revoked key. Mint a new one at Settings and API.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "`upgrade_required`. The public API is Growth plan and above. Free and Starter never get it; a trial keeps it for 14 days.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "`insufficient_scope`. The key lacks `usage:read`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`. Each key may make 120 requests a minute and 10,000 a UTC day. Every response carries `RateLimit` and `RateLimit-Policy` headers; a 429 adds `Retry-After`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "description": "Remaining requests and seconds to reset, per window: `\"minute\";r=119;t=42, \"day\";r=9990;t=3600`.",
                "schema": {
                  "type": "string"
                }
              },
              "RateLimit-Policy": {
                "description": "The windows: `\"minute\";q=120;w=60, \"day\";q=10000;w=86400`.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "On a 429 only: seconds to wait before the next request.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callMcp",
        "summary": "MCP JSON-RPC endpoint",
        "description": "One POST path that speaks MCP over JSON-RPC 2.0. Send `initialize`, then `tools/list`, then `tools/call`.\n\nAuthenticate one of two ways. An OAuth 2.1 access token (`Authorization: Bearer rw_oat_…`) can carry `read`, `write` and `spend`. A workspace API key reads, and a key created with \"Allow changes\" also uses the write tools of the toolsets its scopes open. An API key never gets `spend` here, so a leaked key can never spend.\n\nA tool whose entry says `requiresIdempotencyKey` must carry `idempotency_key` in its arguments. Reuse the same key when you retry, or a timeout can charge twice.\n\nA gate failure (plan, allowance, credits) comes back as a tool result marked `isError`, with the reason and the URL that fixes it. It is not a JSON-RPC error, because a model cannot read one.",
        "tags": [
          "Agent API (MCP)"
        ],
        "security": [
          {
            "oauth2": [
              "read"
            ]
          },
          {
            "oauth2": [
              "read",
              "write"
            ]
          },
          {
            "oauth2": [
              "read",
              "write",
              "spend"
            ]
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "const": "2.0"
                  },
                  "id": {
                    "type": [
                      "string",
                      "integer"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "examples": [
                      "initialize",
                      "tools/list",
                      "tools/call"
                    ]
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "For `tools/call`: `{ name, arguments }`. `name` is one of the tools in `x-mcp-tools`.",
                    "properties": {
                      "name": {
                        "type": "string",
                        "enum": [
                          "get_workspace",
                          "get_plan_and_credits",
                          "list_sites",
                          "pause_site",
                          "resume_site",
                          "create_checkout_link",
                          "list_domains",
                          "add_domain",
                          "recrawl_domain",
                          "remove_domain",
                          "list_questions",
                          "add_question",
                          "remove_question",
                          "get_scorecard",
                          "list_citations",
                          "get_share_of_voice",
                          "list_visibility_events",
                          "run_citation_check",
                          "refresh_share_of_voice",
                          "list_opportunities",
                          "refresh_opportunities",
                          "dismiss_opportunity",
                          "list_briefs",
                          "get_brief",
                          "create_brief",
                          "update_brief",
                          "archive_brief",
                          "approve_brief",
                          "list_articles",
                          "get_article",
                          "generate_article",
                          "publish_article",
                          "replace_article",
                          "bulk_replace_articles",
                          "get_autopilot",
                          "set_autopilot",
                          "get_planner",
                          "move_planner_card",
                          "list_keywords",
                          "add_keywords",
                          "get_search_console_summary",
                          "list_fixes",
                          "preview_fixes"
                        ]
                      },
                      "arguments": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC response. A failed tool is a 200 with `result.isError` true, not an HTTP error.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "No credential, or an expired token. The `WWW-Authenticate` header names the resource metadata document to discover the OAuth server.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          }
        }
      },
      "x-mcp-tools": [
        {
          "name": "get_workspace",
          "title": "Get workspace",
          "description": "Show the Rankwise workspace this connection acts in: its name, kind (personal or agency client), your role in it, and the permissions this connection has. Every other account tool works inside this one workspace.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "workspace": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "kind": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string"
                  }
                },
                "required": [],
                "additionalProperties": true
              },
              "role": {
                "type": "string"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "connected_via": {
                "type": "string"
              },
              "dashboard_url": {
                "type": "string"
              }
            },
            "required": [
              "workspace",
              "role",
              "scopes"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_plan_and_credits",
          "title": "Get plan and credits",
          "description": "Show the workspace's billing plan, its credit balance, what one approved brief costs in credits, and the plan limits (domains, questions, AI engines, monthly AI checks). Use it before a tool that spends credits or a plan allowance. A plan of 'paused' means the trial ended or the subscription was canceled without a new plan: nothing is deleted, but checks and writing stay stopped until the workspace has an active plan again. pricing_url describes the plans.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "plan": {
                "type": "string"
              },
              "credits": {
                "type": "number"
              },
              "agency_billing": {
                "type": "boolean"
              },
              "brief_draft_cost_credits": {
                "type": "number"
              },
              "can_publish_to_cms": {
                "type": "boolean"
              },
              "limits": {
                "type": "object",
                "properties": {
                  "max_domains": {
                    "type": "number"
                  },
                  "max_questions_per_domain": {
                    "type": "number"
                  },
                  "engines": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "monthly_check_budget": {
                    "type": "number"
                  },
                  "on_demand_checks_per_month": {
                    "type": "number"
                  }
                },
                "required": [],
                "additionalProperties": true
              },
              "current_period_end": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "trial_ends_at": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "billing_url": {
                "type": "string"
              },
              "pricing_url": {
                "type": "string"
              }
            },
            "required": [
              "plan",
              "credits",
              "limits"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_sites",
          "title": "List sites",
          "description": "List the site this connection reaches: its id (the workspace id), name, tracked domains, and whether automatic articles are on, how many a week, and whether they are paused. A connection reaches one site; connect again (or add a CLI profile) for another.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "sites": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The site id. It is the workspace id."
                    },
                    "name": {
                      "type": "string"
                    },
                    "domains": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "domain": {
                            "type": "string"
                          }
                        },
                        "required": [],
                        "additionalProperties": true
                      }
                    },
                    "automatic_articles": {
                      "type": "object",
                      "properties": {
                        "mode": {
                          "type": "string"
                        },
                        "articles_per_week": {
                          "type": "integer"
                        },
                        "paused": {
                          "type": "boolean"
                        },
                        "paused_reason": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      },
                      "required": [],
                      "additionalProperties": true
                    },
                    "planner_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "domains",
                    "automatic_articles"
                  ],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "sites"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "pause_site",
          "title": "Pause automatic articles",
          "description": "Pause automatic articles for the site. While paused nothing runs on its own: no planner fill, no drafting, no publishing, no credits used. Manual actions still work. Resume with resume_site.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "site_id": {
                "description": "The site id from list_sites. Defaults to this connection's site.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "site": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The site id. It is the workspace id."
                  },
                  "name": {
                    "type": "string"
                  },
                  "domains": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "domain": {
                          "type": "string"
                        }
                      },
                      "required": [],
                      "additionalProperties": true
                    }
                  },
                  "automatic_articles": {
                    "type": "object",
                    "properties": {
                      "mode": {
                        "type": "string"
                      },
                      "articles_per_week": {
                        "type": "integer"
                      },
                      "paused": {
                        "type": "boolean"
                      },
                      "paused_reason": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "required": [],
                    "additionalProperties": true
                  },
                  "planner_url": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name",
                  "domains",
                  "automatic_articles"
                ],
                "additionalProperties": true
              }
            },
            "required": [
              "site"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "resume_site",
          "title": "Resume automatic articles",
          "description": "Resume automatic articles for the site after a pause. Cards left on days that passed move to the next free publishing days. Resuming is free.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "site_id": {
                "description": "The site id from list_sites. Defaults to this connection's site.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "site": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The site id. It is the workspace id."
                  },
                  "name": {
                    "type": "string"
                  },
                  "domains": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "domain": {
                          "type": "string"
                        }
                      },
                      "required": [],
                      "additionalProperties": true
                    }
                  },
                  "automatic_articles": {
                    "type": "object",
                    "properties": {
                      "mode": {
                        "type": "string"
                      },
                      "articles_per_week": {
                        "type": "integer"
                      },
                      "paused": {
                        "type": "boolean"
                      },
                      "paused_reason": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "required": [],
                    "additionalProperties": true
                  },
                  "planner_url": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "name",
                  "domains",
                  "automatic_articles"
                ],
                "additionalProperties": true
              }
            },
            "required": [
              "site"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "create_checkout_link",
          "title": "Create a checkout link",
          "description": "Create a Stripe Checkout link for a self-serve Rankwise plan (starter, growth or scale) for this workspace's account, and give it to the person. Nothing is charged by this call: the person opens the link and pays in their browser. If the account already has an active plan, the link opens the billing page to confirm the plan change instead. Agency plans are set up with the Rankwise team. Send a unique idempotency_key and reuse it on a retry.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "plan": {
                "type": "string",
                "enum": [
                  "starter",
                  "growth",
                  "scale"
                ]
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "plan",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "checkout_url": {
                "type": "string"
              },
              "plan": {
                "type": "string"
              },
              "plan_name": {
                "type": "string"
              },
              "price_usd_per_month": {
                "type": "number"
              },
              "charged": {
                "type": "boolean"
              },
              "note": {
                "type": "string"
              }
            },
            "required": [
              "checkout_url",
              "plan",
              "charged"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_domains",
          "title": "List tracked domains",
          "description": "List the domains this workspace tracks for AI visibility, with each domain's id, composite visibility score (0 to 100, null when not scored yet), number of tracked questions, how many questions AI engines mention the brand for, and the last crawl time. Use the id with the other domain tools.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "domains": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "domain": {
                      "type": "string"
                    },
                    "score": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "question_count": {
                      "type": "integer"
                    },
                    "mentioned_questions": {
                      "type": "integer"
                    },
                    "page_count": {
                      "type": "integer"
                    },
                    "last_crawled_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "collecting_results": {
                      "type": "boolean"
                    },
                    "dashboard_url": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "domains"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "add_domain",
          "title": "Add a domain",
          "description": "Start tracking a domain's AI visibility in this workspace. Rankwise seeds the homepage and crawls and scores it in the background. Fails when the plan's domain limit is reached. Free: it uses no credits.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain": {
                "description": "The domain, e.g. example.com",
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              "brand_domains": {
                "description": "Other domains of the same brand, counted as citations of it.",
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "maxLength": 253
                }
              }
            },
            "required": [
              "domain"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "domain": {
                "type": "string"
              },
              "dashboard_url": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "recrawl_domain",
          "title": "Re-crawl a domain",
          "description": "Queue a fresh crawl and re-score of a tracked domain's pages. It runs in the background and takes a few minutes; read get_scorecard afterwards. Free: it uses no credits.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "queued_pages": {
                "type": "integer"
              },
              "discovered_pages": {
                "type": "integer"
              }
            },
            "required": [],
            "additionalProperties": true
          }
        },
        {
          "name": "remove_domain",
          "title": "Remove a domain",
          "description": "Stop tracking a domain and permanently delete its questions, AI answers, scores and history. This cannot be undone.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "removed": {
                "type": "boolean"
              },
              "domain": {
                "type": "string"
              }
            },
            "required": [
              "removed"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_questions",
          "title": "List tracked questions",
          "description": "List the questions tracked for a domain (the prompts Rankwise asks AI engines), each with its id, market locale, and the latest check result: cited, not_cited or error, the citation position and when it ran.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "questions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "question": {
                      "type": "string"
                    },
                    "locale": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "type": "string"
                    },
                    "last_result": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "last_checked_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "cited_position": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "questions"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "add_question",
          "title": "Add a question",
          "description": "Track a new question for a domain, e.g. \"best invoicing software for freelancers\". Scheduled checks then ask the plan's AI engines whether they cite the brand. Fails at the plan's question limit. Free: it uses no credits.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "question": {
                "description": "The question, as a user would ask an AI engine.",
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              },
              "locale": {
                "description": "Market locale such as en-US or de-DE. Omit for the default market.",
                "type": "string",
                "maxLength": 20
              }
            },
            "required": [
              "domain_id",
              "question"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              }
            },
            "required": [
              "id"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "remove_question",
          "title": "Remove a question",
          "description": "Stop tracking a question and delete its check history. This cannot be undone.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "question_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "question_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "removed": {
                "type": "boolean"
              }
            },
            "required": [
              "removed"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_scorecard",
          "title": "Get AI visibility scorecard",
          "description": "Read a domain's AI Visibility Scorecard: the composite score (0 to 100, null when nothing is measured yet) and the latest score, confidence and recommendations for each dimension.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "type": "string"
              },
              "composite_score": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "dimensions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "dimension": {
                      "type": "string"
                    },
                    "score": {
                      "type": "number"
                    },
                    "confidence": {
                      "type": "string"
                    },
                    "recommendations": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "computed_at": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "dashboard_url": {
                "type": "string"
              }
            },
            "required": [
              "domain_id",
              "composite_score",
              "dimensions"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_citations",
          "title": "List AI citations",
          "description": "For each tracked question and AI engine, show the latest real measurement: whether the engine cited the brand, at which position, which URLs it cited, and when. An engine that failed to answer is skipped rather than counted as not cited.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "limit": {
                "description": "Maximum rows to return.",
                "default": 200,
                "type": "integer",
                "minimum": 1,
                "maximum": 500
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "domain": {
                "type": "string"
              },
              "citations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "question_id": {
                      "type": "string"
                    },
                    "question": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "engine": {
                      "type": "string"
                    },
                    "engine_label": {
                      "type": "string"
                    },
                    "cited": {
                      "type": "boolean"
                    },
                    "position": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "cited_urls": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "locale": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "checked_at": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "total": {
                "type": "integer"
              }
            },
            "required": [
              "citations"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_share_of_voice",
          "title": "Get AI share of voice",
          "description": "Read a domain's latest AI Share of Voice snapshot: the brand's share of AI answers, its own citations and mentions, the competitor leaderboard, and up to 12 earlier snapshots. Null when it was never measured.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "domain": {
                "type": "string"
              },
              "measured": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "history": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "captured_at": {
                      "type": "string"
                    },
                    "share_of_voice": {
                      "type": "number"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "domain",
              "measured"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_visibility_events",
          "title": "List visibility events",
          "description": "List recent AI visibility events in the workspace, newest first: citations won and lost, fixes proposed, goals reached. Optionally only since a date or for one domain.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "since": {
                "description": "ISO 8601 date-time; only events after it.",
                "type": "string",
                "format": "date-time",
                "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
              },
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "limit": {
                "default": 50,
                "type": "integer",
                "minimum": 1,
                "maximum": 200
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "events": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "domain": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "domain_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "detail": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "created_at": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "events"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "run_citation_check",
          "title": "Run an AI citation check",
          "description": "Ask the plan's AI engines one tracked question now and record whether each cites the brand. Engines checked in the last few hours are served from that result at no cost. Uses the workspace's monthly on-demand check allowance. Send a unique idempotency_key, and the same one on a retry.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "question_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "question_id",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "ok": {
                "type": "boolean"
              },
              "message": {
                "type": "string"
              },
              "engines": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "engine": {
                      "type": "string"
                    },
                    "result": {
                      "type": "string"
                    },
                    "position": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "from_recent_check": {
                      "type": "boolean"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "checked": {
                "type": "integer"
              },
              "served_fresh": {
                "type": "integer"
              },
              "remaining_refreshes_this_month": {
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "ok",
              "message",
              "engines"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "refresh_share_of_voice",
          "title": "Refresh AI share of voice",
          "description": "Capture a fresh AI Share of Voice snapshot for a domain from DataForSEO LLM Mentions. A snapshot from the last 12 hours is returned instead of buying a new one, because the index lags by days. Send a unique idempotency_key, and the same one on a retry.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "domain_id",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "captured": {
                "type": "boolean"
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "share_of_voice": {
                "type": [
                  "number",
                  "null"
                ]
              }
            },
            "required": [
              "captured"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_opportunities",
          "title": "List content opportunities",
          "description": "List the workspace's ranked content opportunities: topics where AI engines answer questions the brand is not cited for, scored by demand, citation gap and feasibility. Dismissed topics are left out. Each item says whether a brief or article already covers it.",
          "scope": "read",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "limit": {
                "default": 25,
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "opportunities": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "topic": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "queries": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "score": {
                      "type": "number"
                    },
                    "status": {
                      "type": "string"
                    },
                    "brief_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "coverage": {}
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "total": {
                "type": "integer"
              }
            },
            "required": [
              "opportunities",
              "total"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "refresh_opportunities",
          "title": "Refresh content opportunities",
          "description": "Recompute the workspace's opportunity queue from its tracked questions and AI citation data, and look for new topics. Uses paid search and AI data, so it runs at most once every 10 minutes per workspace. Send a unique idempotency_key; retry with the same key.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "created": {
                "type": "integer"
              },
              "refreshed": {
                "type": "integer"
              },
              "discovered": {
                "type": "integer"
              }
            },
            "required": [
              "created",
              "refreshed",
              "discovered"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "dismiss_opportunity",
          "title": "Dismiss a content opportunity",
          "description": "Remove one topic from the workspace's opportunity queue. It can be restored in the Rankwise app (Demand page). Nothing is deleted.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "opportunity_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "opportunity_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "status"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_briefs",
          "title": "List briefs",
          "description": "List the workspace's content briefs, newest first: drafts waiting for approval (including ones Rankwise suggested), approved pieces being written, and finished ones. Filter by status. An expert sees only the briefs assigned to them.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "draft",
                  "approved",
                  "assigned",
                  "in_progress",
                  "completed",
                  "archived"
                ]
              },
              "limit": {
                "default": 25,
                "type": "integer",
                "minimum": 1,
                "maximum": 100
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "briefs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": "string"
                    },
                    "topic": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "type": "string"
                    },
                    "auto_generated": {
                      "type": "boolean"
                    },
                    "approved_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "draft_article_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "target_queries": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "total": {
                "type": "integer"
              }
            },
            "required": [
              "briefs",
              "total"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_brief",
          "title": "Get a brief",
          "description": "Read one brief in full: title, topic, intent, target questions, outline, research notes, suggested sources, status, and the draft article once it exists.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "brief_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "editable": {
                "type": "boolean"
              },
              "target_queries": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "outline": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "draft_article_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "approved_at": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "title",
              "status"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "create_brief",
          "title": "Create a brief",
          "description": "Create a draft brief for an article. Nothing is written or charged until the brief is approved with approve_brief. If tracked_domain_id is left out, the workspace's first tracked domain grounds the brief.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": false,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "title": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "topic": {
                "type": "string",
                "maxLength": 500
              },
              "intent": {
                "type": "string",
                "maxLength": 500
              },
              "target_queries": {
                "default": [],
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "tracked_domain_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "tone": {
                "type": "string",
                "maxLength": 120
              },
              "audience": {
                "type": "string",
                "maxLength": 300
              },
              "language": {
                "type": "string",
                "maxLength": 60
              }
            },
            "required": [
              "title"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "brief_id"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "update_brief",
          "title": "Update a brief",
          "description": "Edit a draft brief before it is approved: title, topic, intent, target questions or outline. An approved brief cannot be edited; edit its draft article in the app instead.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "title": {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              "topic": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 500
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "intent": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 500
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "target_queries": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "outline": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              }
            },
            "required": [
              "brief_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string"
              },
              "updated": {
                "type": "boolean"
              }
            },
            "required": [
              "brief_id"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "archive_brief",
          "title": "Archive a brief",
          "description": "Remove a draft brief that was never approved. Approved briefs cannot be archived because their credits were spent. The brief can be restored in the app, and its topic goes back to the opportunity queue.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "reason": {
                "type": "string",
                "enum": [
                  "wrong_topic",
                  "wrong_tone",
                  "factual_concern",
                  "other"
                ]
              },
              "note": {
                "type": "string",
                "maxLength": 300
              }
            },
            "required": [
              "brief_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            },
            "required": [
              "brief_id",
              "status"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "approve_brief",
          "title": "Approve a brief",
          "description": "Approve a draft brief. This debits the workspace's credits (see get_plan_and_credits for the cost) and starts writing the AI draft article, which then waits for review; nothing is published. Re-approving a draft whose generation failed is free. Send a unique idempotency_key and reuse it on retry.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "brief_id",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "brief_id": {
                "type": "string"
              },
              "approved": {
                "type": "boolean"
              },
              "cost_credits": {
                "type": "number"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "brief_id",
              "approved"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_articles",
          "title": "List articles",
          "description": "List the articles in this workspace, newest first: title, status (generating, ready, published, failed), publish status and published URL. Experts see only the drafts assigned to them. Filter by status or title words.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "status": {
                "description": "ready, generating, published, failed or unpublished",
                "type": "string",
                "enum": [
                  "ready",
                  "generating",
                  "published",
                  "failed",
                  "unpublished"
                ]
              },
              "query": {
                "description": "Words in the title",
                "type": "string",
                "maxLength": 200
              },
              "page": {
                "default": 1,
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991
              },
              "page_size": {
                "default": 20,
                "type": "integer",
                "minimum": 1,
                "maximum": 50
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "articles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "title": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "keyword": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "status": {
                      "type": "string"
                    },
                    "publish_status": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "published_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "integration_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "brief_id": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "expert_review_state": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "created_at": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "total": {
                "type": "integer"
              },
              "page": {
                "type": "integer"
              },
              "page_size": {
                "type": "integer"
              }
            },
            "required": [
              "articles",
              "total"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_article",
          "title": "Get article",
          "description": "Read one article in this workspace: its metadata, status, meta description, the first 4,000 characters of its text (or the full HTML with include_html), the sources it cites, and the Article and FAQ structured data (JSON-LD) that ships with it. Use list_articles to find the id.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "article_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "include_html": {
                "description": "Also return the full article body as HTML.",
                "default": false,
                "type": "boolean"
              }
            },
            "required": [
              "article_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "article": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "keyword": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "publish_status": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "published_url": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "integration_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "brief_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "expert_review_state": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "created_at": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "required": [],
                "additionalProperties": true
              },
              "meta_description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "slug": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "html": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "body_excerpt": {
                "type": "string"
              },
              "body_truncated": {
                "type": "boolean"
              },
              "last_error_code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sources": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "title": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "url"
                  ],
                  "additionalProperties": true
                }
              },
              "schema_jsonld": {}
            },
            "required": [
              "article"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "generate_article",
          "title": "Generate article",
          "description": "Write a new AI article for a keyword. It uses the same research-and-cite writer as Autopilot: real sources, links only to pages that exist, a closing call to action, and Article and FAQ schema. This spends workspace credits (1 for short, 2 for medium, 3 for long, 4 for comprehensive; check get_plan_and_credits first). The article is generated in the background and is NOT published: call publish_article for that. Retries with the same idempotency_key never spend twice.",
          "scope": "spend",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "keyword": {
                "description": "The topic or search keyword",
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              "length": {
                "description": "short 1,200-1,600 words, medium 1,600-2,400 (default), long 2,400-3,200, comprehensive 3,200-4,200",
                "type": "string",
                "enum": [
                  "short",
                  "medium",
                  "long",
                  "comprehensive"
                ]
              },
              "article_type": {
                "description": "auto (default, chosen from the keyword), how_to, explainer, comparison, reference or listicle",
                "type": "string",
                "enum": [
                  "auto",
                  "how_to",
                  "explainer",
                  "comparison",
                  "reference",
                  "listicle"
                ]
              },
              "tone": {
                "type": "string",
                "maxLength": 100
              },
              "language": {
                "type": "string",
                "pattern": "^[a-z]{2}$"
              },
              "integration_id": {
                "description": "A connected CMS in this workspace, used for internal links and later publishing",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "keyword",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "article": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "title": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "keyword": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "status": {
                    "type": "string"
                  },
                  "publish_status": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "published_url": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "integration_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "brief_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "expert_review_state": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "created_at": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "required": [],
                "additionalProperties": true
              },
              "credits_spent": {
                "type": "number"
              },
              "already_existed": {
                "type": "boolean"
              },
              "next_step": {
                "type": "string"
              }
            },
            "required": [
              "article"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "publish_article",
          "title": "Publish article",
          "description": "Publish one article to the workspace's connected CMS (WordPress, WordPress.com, Shopify, Webflow, Wix, Ghost, Notion, Framer or a self-hosted site). This makes it live on the customer's website. A brief draft must be approved by its expert first. If the workspace has several CMS connections and no default destination, name one with integration_id. Pass publish_at (an ISO date-time) to schedule it, or \"next_slot\" for the workspace's next publish time.",
          "scope": "write",
          "workspaceRoles": [
            "admin",
            "expert"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": false,
          "requiresIdempotencyKey": true,
          "inputSchema": {
            "type": "object",
            "properties": {
              "article_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "integration_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "publish_at": {
                "anyOf": [
                  {
                    "type": "string",
                    "const": "next_slot"
                  },
                  {
                    "type": "string",
                    "format": "date-time",
                    "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
                  }
                ]
              },
              "idempotency_key": {
                "type": "string",
                "minLength": 8,
                "maxLength": 200
              }
            },
            "required": [
              "article_id",
              "idempotency_key"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "article_id": {
                "type": "string"
              },
              "integration_id": {
                "type": "string"
              },
              "job_id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "already_queued": {
                "type": "boolean"
              },
              "scheduled_for": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "next_step": {
                "type": "string"
              }
            },
            "required": [
              "article_id",
              "integration_id"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "replace_article",
          "title": "Replace an article",
          "description": "Replace an article's title, meta description, slug or full HTML body. Send only the fields to change. The slug must be unique in the workspace. Open tracked changes are dropped when the body changes. A published article's live post is not changed; publish it again to send the new version. Free.",
          "scope": "write",
          "workspaceRoles": [
            "admin",
            "expert"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "article_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "title": {
                "type": "string",
                "maxLength": 400
              },
              "meta_description": {
                "type": "string",
                "maxLength": 600
              },
              "slug": {
                "type": "string",
                "maxLength": 400
              },
              "html": {
                "description": "The full article body as HTML. It is sanitised: scripts, styles, frames, forms and event handlers are removed.",
                "type": "string",
                "maxLength": 200001
              }
            },
            "required": [
              "article_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "article": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "changed": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "title": {
                    "type": "string"
                  },
                  "meta_description": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "slug": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "live_copy_unchanged": {
                    "type": "boolean"
                  },
                  "url": {
                    "type": "string"
                  }
                },
                "required": [
                  "id",
                  "changed"
                ],
                "additionalProperties": true
              }
            },
            "required": [
              "article"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "bulk_replace_articles",
          "title": "Replace several articles",
          "description": "Replace up to 50 articles in one call, with the same rules as replace_article. Each article succeeds or fails on its own; the result lists both.",
          "scope": "write",
          "workspaceRoles": [
            "admin",
            "expert"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "articles": {
                "minItems": 1,
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "article_id": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    },
                    "title": {
                      "type": "string",
                      "maxLength": 400
                    },
                    "meta_description": {
                      "type": "string",
                      "maxLength": 600
                    },
                    "slug": {
                      "type": "string",
                      "maxLength": 400
                    },
                    "html": {
                      "description": "The full article body as HTML. It is sanitised: scripts, styles, frames, forms and event handlers are removed.",
                      "type": "string",
                      "maxLength": 200001
                    }
                  },
                  "required": [
                    "article_id"
                  ],
                  "additionalProperties": false
                }
              }
            },
            "required": [
              "articles"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "replaced": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "changed": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "title": {
                      "type": "string"
                    },
                    "meta_description": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "slug": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "live_copy_unchanged": {
                      "type": "boolean"
                    },
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "changed"
                  ],
                  "additionalProperties": true
                }
              },
              "failed": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "article_id": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "replaced",
              "failed"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_autopilot",
          "title": "Get autopilot settings",
          "description": "Show the workspace's content autopilot: its mode (off, draft_only, requires_approval, full_auto), weekly article quota, whether it is paused, the plan's quota ceiling, suggestions waiting for a decision, and the upcoming approval days.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "string"
              },
              "weekly_quota": {
                "type": "integer"
              },
              "paused_reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "plan": {
                "type": "string"
              },
              "plan_ceiling": {
                "type": "integer"
              },
              "pending_suggestions": {
                "type": "integer"
              },
              "approved_this_week": {
                "type": "integer"
              },
              "scheduled_runs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string"
                    },
                    "quota": {
                      "type": "integer"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "connected_integrations": {
                "type": "integer"
              },
              "article_credit_cost": {
                "type": "number"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "mode",
              "weekly_quota",
              "plan"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "set_autopilot",
          "title": "Change autopilot settings",
          "description": "Change the workspace's content autopilot. mode: off, draft_only (only suggests briefs, spends nothing) or requires_approval (approves up to the weekly quota of suggested briefs, which spends credits, and holds every draft for review). weekly_quota is capped by the plan. paused pauses or resumes. Auto-publishing (full_auto) cannot be switched on here; do that in the Rankwise app.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": true,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "mode": {
                "description": "full_auto is refused: switch on auto-publishing in the app.",
                "type": "string",
                "enum": [
                  "off",
                  "draft_only",
                  "requires_approval",
                  "full_auto"
                ]
              },
              "weekly_quota": {
                "type": "integer",
                "minimum": 1,
                "maximum": 7
              },
              "paused": {
                "type": "boolean"
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "updated": {
                "type": "boolean"
              },
              "mode": {
                "type": "string"
              }
            },
            "required": [
              "updated"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_planner",
          "title": "Get the Content Planner",
          "description": "Read the Content Planner: one card per publishing day with its title, keyword, article type, state (planned, writing, review, published, failed), and search volume and difficulty when measured. Defaults to the window the planner page shows; pass from and to (YYYY-MM-DD, at most 120 days apart) for another. Cards waiting for a day come back under unscheduled.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              "to": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string"
              },
              "to": {
                "type": "string"
              },
              "cards": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The card id (use it with move_planner_card)."
                    },
                    "day": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "title": {
                      "type": "string"
                    },
                    "keyword": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "state": {
                      "type": "string"
                    },
                    "article_type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "article_length": {
                      "type": "string"
                    },
                    "volume": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "difficulty": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "published_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "dashboard_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "day",
                    "title",
                    "keyword",
                    "state"
                  ],
                  "additionalProperties": true
                }
              },
              "unscheduled": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The card id (use it with move_planner_card)."
                    },
                    "day": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "title": {
                      "type": "string"
                    },
                    "keyword": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "state": {
                      "type": "string"
                    },
                    "article_type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "article_length": {
                      "type": "string"
                    },
                    "volume": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "difficulty": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "published_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "dashboard_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "day",
                    "title",
                    "keyword",
                    "state"
                  ],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "from",
              "to",
              "cards",
              "unscheduled"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "move_planner_card",
          "title": "Move a planner card",
          "description": "Move a card that is not written yet to another publishing day. If another unwritten card holds that day, the two swap. A day held by an article that is being written or is published is refused. Free.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "card_id": {
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              },
              "day": {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              }
            },
            "required": [
              "card_id",
              "day"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "moved": {
                "type": "boolean"
              },
              "day": {
                "type": "string"
              },
              "swapped_with": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "moved",
              "day"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_keywords",
          "title": "List keywords",
          "description": "List the keywords in the Content Planner, one per card, with the article title, its day, state, and search volume and difficulty when measured. Filter by state. To export them as CSV, call GET /api/v1/keywords?format=csv.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "state": {
                "description": "planned, writing, review, published or failed",
                "type": "string",
                "enum": [
                  "planned",
                  "writing",
                  "review",
                  "published",
                  "failed"
                ]
              }
            },
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "keywords": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The card id (use it with move_planner_card)."
                    },
                    "day": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "title": {
                      "type": "string"
                    },
                    "keyword": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "state": {
                      "type": "string"
                    },
                    "article_type": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "article_length": {
                      "type": "string"
                    },
                    "volume": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "difficulty": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "published_url": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "dashboard_url": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "day",
                    "title",
                    "keyword",
                    "state"
                  ],
                  "additionalProperties": true
                }
              },
              "total": {
                "type": "integer"
              }
            },
            "required": [
              "keywords",
              "total"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "add_keywords",
          "title": "Add keywords to the planner",
          "description": "Add up to 50 keywords to the Content Planner. Each becomes a card. With a day it takes that day (an unwritten card there moves to the next free day); without one it takes the next free publishing day. Keywords already planned are skipped, so a retry never adds twice. Free: articles are drafted when their day comes.",
          "scope": "write",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": false,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "keywords": {
                "description": "Keywords as strings, or objects with keyword, day, article_type and article_length.",
                "minItems": 1,
                "maxItems": 50,
                "type": "array",
                "items": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "keyword": {
                          "type": "string"
                        },
                        "day": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                        },
                        "article_type": {
                          "type": "string",
                          "enum": [
                            "how_to",
                            "explainer",
                            "comparison",
                            "reference",
                            "listicle"
                          ]
                        },
                        "article_length": {
                          "type": "string",
                          "enum": [
                            "auto",
                            "short",
                            "medium",
                            "long",
                            "comprehensive"
                          ]
                        }
                      },
                      "required": [
                        "keyword"
                      ],
                      "additionalProperties": false
                    }
                  ]
                }
              }
            },
            "required": [
              "keywords"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "added": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "keyword": {
                      "type": "string"
                    },
                    "card_id": {
                      "type": "string"
                    },
                    "moved_another_card": {
                      "type": "boolean"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "skipped": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "keyword": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "failed": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "keyword": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "added",
              "skipped",
              "failed"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "get_search_console_summary",
          "title": "Get Search Console summary",
          "description": "Read the site's Google Search Console numbers for the last 28 days: total clicks and impressions, and the best articles by clicks. connected is false until Search Console is connected and has synced once.",
          "scope": "read",
          "workspaceRoles": [
            "admin",
            "expert",
            "viewer"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {},
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "connected": {
                "type": "boolean"
              },
              "days": {
                "type": "integer"
              },
              "clicks": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "impressions": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "best_articles": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "clicks": {
                      "type": "number"
                    },
                    "impressions": {
                      "type": "number"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "connect_url": {
                "type": "string"
              }
            },
            "required": [
              "connected",
              "days",
              "best_articles"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "list_fixes",
          "title": "List proposed fixes",
          "description": "List the on-page fixes Rankwise proposes for a domain (structured data, head tags, robots rules and similar), each with the page pattern it targets, the dimension it improves, why, and its status. Rankwise does not change the site; the user or their developer applies a fix.",
          "scope": "read",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "fixes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "task": {
                      "type": "string"
                    },
                    "why": {
                      "type": "string"
                    },
                    "dimension": {
                      "type": "string"
                    },
                    "page_pattern": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "detail": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "rationale": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              },
              "dashboard_url": {
                "type": "string"
              }
            },
            "required": [
              "fixes"
            ],
            "additionalProperties": true
          }
        },
        {
          "name": "preview_fixes",
          "title": "Preview proposed fixes",
          "description": "Show the exact change each proposed fix would make to the domain's pages, as a before and after diff. A dry run: it reads the live pages and changes nothing.",
          "scope": "read",
          "workspaceRoles": [
            "admin"
          ],
          "readOnly": true,
          "destructive": false,
          "idempotent": true,
          "requiresIdempotencyKey": false,
          "inputSchema": {
            "type": "object",
            "properties": {
              "domain_id": {
                "description": "The tracked domain's id, from list_domains.",
                "type": "string",
                "format": "uuid",
                "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
              }
            },
            "required": [
              "domain_id"
            ],
            "additionalProperties": false
          },
          "outputSchema": {
            "type": "object",
            "properties": {
              "previews": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "fix_key": {
                      "type": "string"
                    },
                    "result": {
                      "type": "string"
                    },
                    "diff": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "message": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [],
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "previews"
            ],
            "additionalProperties": true
          }
        }
      ],
      "x-mcp-scopes": {
        "read": "Read the workspace. Never changes data and never spends.",
        "write": "Change the workspace: add a domain, write a brief, publish an article.",
        "spend": "Spend plan credits: run a citation check, refresh share of voice, generate an article.",
        "offline_access": "Keep a refresh token. Grants no tool access of its own."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A workspace API key, `rw_live_…`, from Settings and Developers. Growth plan and above. Read-only by default. A key created with \"Allow changes\" gets the write scopes, on `/api/v1` and on `/api/mcp` (where it opens the matching toolsets only). A key created with the `audit:run` scope may also call `POST /api/v1/audits`, and nothing else that spends. Scopes: sites:read: List the site and its automatic-article status. keywords:read: List and export the planner keywords. articles:read: List and read articles. planner:read: Read the Content Planner. gsc:read: Read the Search Console summary. usage:read: Read the plan, credits, limits and this key's entitlements. sites:write: Pause and resume automatic articles. Free. keywords:write: Add keywords to the Content Planner. Free. articles:write: Replace an article's title, meta description, slug or body. Free. planner:write: Move planner cards between days. Free. read: Every key has it. Reads everything: it grants all `*:read` scopes. audit:run: Start a fresh audit of a tracked domain, at 1 plan credit per audit, up to the key's daily cap. Ticked when the key is created, never added later. It allows that one action and no other write or spend."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "In-house OAuth 2.1 with PKCE and dynamic client registration. One token acts as one user in one workspace, chosen on the consent screen.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://tryrankwise.com/oauth/authorize",
            "tokenUrl": "https://tryrankwise.com/api/oauth/token",
            "refreshUrl": "https://tryrankwise.com/api/oauth/token",
            "scopes": {
              "read": "Read the workspace. Never changes data and never spends.",
              "write": "Change the workspace: add a domain, write a brief, publish an article.",
              "spend": "Spend plan credits: run a citation check, refresh share of voice, generate an article.",
              "offline_access": "Keep a refresh token. Grants no tool access of its own."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine code. Branch on this, never on the message prose.",
                "examples": [
                  "missing_domain",
                  "domain_not_found",
                  "upgrade_required"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable reason, and how to resolve it."
              }
            }
          }
        }
      },
      "ApiIndex": {
        "type": "object",
        "description": "Self-describing catalogue. Needs no key.",
        "required": [
          "object",
          "service",
          "version",
          "endpoints"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "index"
          },
          "service": {
            "type": "string",
            "const": "rankwise"
          },
          "version": {
            "type": "string"
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          },
          "authentication": {
            "type": "string"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "method",
                "path",
                "description"
              ],
              "properties": {
                "method": {
                  "type": "string"
                },
                "path": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "agentApi": {
            "type": "object",
            "properties": {
              "mcp": {
                "type": "string"
              },
              "note": {
                "type": "string"
              }
            }
          }
        }
      },
      "Citations": {
        "type": "object",
        "description": "Latest citation status per query and per engine, with the URLs each engine cited.",
        "required": [
          "object",
          "domain",
          "generatedAt",
          "summary",
          "surfaces",
          "queries"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "citations"
          },
          "domain": {
            "type": "string",
            "description": "Bare hostname."
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "summary": {
            "type": "object",
            "required": [
              "queriesTotal",
              "queriesCited",
              "queriesNotCited",
              "queriesNotProbed",
              "citationRate"
            ],
            "properties": {
              "queriesTotal": {
                "type": "integer"
              },
              "queriesCited": {
                "type": "integer"
              },
              "queriesNotCited": {
                "type": "integer"
              },
              "queriesNotProbed": {
                "type": "integer",
                "description": "Tracked but not yet probed, so neither cited nor not."
              },
              "citationRate": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Percent of tracked queries cited, or null when none."
              }
            }
          },
          "surfaces": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "surface",
                "label",
                "cited",
                "probed",
                "rate"
              ],
              "properties": {
                "surface": {
                  "type": "string",
                  "description": "Engine key.",
                  "examples": [
                    "perplexity",
                    "chatgpt",
                    "google_ai_overviews"
                  ]
                },
                "label": {
                  "type": "string",
                  "description": "Display name of the engine."
                },
                "cited": {
                  "type": "integer",
                  "description": "Queries where we were cited."
                },
                "probed": {
                  "type": "integer",
                  "description": "Queries actually probed."
                },
                "rate": {
                  "type": [
                    "number",
                    "null"
                  ],
                  "description": "Percent cited of probed, or null when nothing was probed."
                }
              }
            }
          },
          "queries": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "query",
                "cited",
                "surfaces"
              ],
              "properties": {
                "query": {
                  "type": "string"
                },
                "locale": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "examples": [
                    "en-US"
                  ]
                },
                "searchVolume": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "description": "Monthly GOOGLE search volume from DataForSEO, or null when never enriched. This is search demand, not AI prompt demand. Do not present it as prompt volume."
                },
                "cited": {
                  "type": "boolean"
                },
                "position": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "lastProbeAt": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                },
                "surfaces": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "required": [
                      "surface",
                      "label",
                      "status",
                      "position",
                      "citedUrls"
                    ],
                    "properties": {
                      "surface": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "cited",
                          "not_cited",
                          "error"
                        ]
                      },
                      "position": {
                        "type": [
                          "integer",
                          "null"
                        ]
                      },
                      "citedUrls": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ShareOfVoice": {
        "type": "object",
        "description": "Latest MEASURED AI share-of-voice snapshot, own domain against competitors.",
        "required": [
          "object",
          "domain",
          "generatedAt",
          "measured",
          "leaderboard"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "share_of_voice"
          },
          "domain": {
            "type": "string"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "measured": {
            "type": "boolean",
            "description": "False until a snapshot exists. When false, read `note` and treat every number as absent, not as zero."
          },
          "capturedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "shareOfVoice": {
            "type": [
              "number",
              "null"
            ],
            "description": "Percent of measured citations and mentions that are ours."
          },
          "ownCitations": {
            "type": [
              "integer",
              "null"
            ]
          },
          "ownMentions": {
            "type": [
              "integer",
              "null"
            ]
          },
          "leaderboard": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "domain",
                "isOwn",
                "citations",
                "mentions"
              ],
              "properties": {
                "domain": {
                  "type": "string"
                },
                "isOwn": {
                  "type": "boolean"
                },
                "citations": {
                  "type": "integer"
                },
                "mentions": {
                  "type": "integer"
                }
              }
            }
          },
          "note": {
            "type": "string",
            "description": "Present only when `measured` is false, and says why."
          }
        }
      },
      "Dimensions": {
        "type": "object",
        "description": "Latest per-dimension AI-visibility scores and confidence.",
        "required": [
          "object",
          "domain",
          "generatedAt",
          "dimensions"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "dimensions"
          },
          "domain": {
            "type": "string"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "dimensions": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "dimension",
                "label",
                "score",
                "confidence",
                "recommendations"
              ],
              "properties": {
                "dimension": {
                  "type": "string",
                  "examples": [
                    "crawler_access",
                    "structured_data"
                  ]
                },
                "label": {
                  "type": "string"
                },
                "score": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 100
                },
                "confidence": {
                  "type": "string",
                  "description": "How much evidence stands behind the score. A low-confidence score is a hint, not a finding."
                },
                "recommendations": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "Events": {
        "type": "object",
        "description": "Visibility events for the key's workspace, newest first. Poll with `since` set to the newest `createdAt` you already hold.",
        "required": [
          "object",
          "generatedAt",
          "count",
          "events"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "events"
          },
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "count": {
            "type": "integer"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "type",
                "domain",
                "createdAt"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "examples": [
                    "citation_won",
                    "citation_lost",
                    "fix_proposed"
                  ]
                },
                "domain": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Hostname. Internal ids are never exposed."
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                },
                "payload": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Shape varies by `type`."
                }
              }
            }
          }
        }
      },
      "Audit": {
        "type": "object",
        "description": "A queued fresh audit. The re-crawl and re-score run in the background; read the new scores from /api/v1/dimensions and /api/v1/citations a few minutes later.",
        "required": [
          "object",
          "id",
          "domain",
          "status",
          "credits_charged",
          "audits_today",
          "daily_cap",
          "replayed"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "audit"
          },
          "id": {
            "type": "string",
            "description": "The spend id. Quote it to support."
          },
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "const": "queued"
          },
          "credits_charged": {
            "type": "integer",
            "description": "Credits this audit cost. A replayed response repeats the original charge; it did not charge again."
          },
          "credits_remaining": {
            "type": "integer"
          },
          "audits_today": {
            "type": "integer",
            "description": "Audits this key has started since 00:00 UTC."
          },
          "daily_cap": {
            "type": "integer"
          },
          "pages_queued": {
            "type": "integer"
          },
          "replayed": {
            "type": "boolean",
            "description": "True when this response answers a retry of an Idempotency-Key that was already charged. Nothing was charged for the retry."
          },
          "note": {
            "type": "string"
          }
        }
      },
      "ApiKeyInfo": {
        "type": "object",
        "description": "What the calling key may do, and what a fresh audit costs.",
        "required": [
          "object",
          "scopes",
          "audits"
        ],
        "properties": {
          "object": {
            "type": "string",
            "const": "api_key"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "read",
                "audit:run"
              ]
            }
          },
          "audits": {
            "type": "object",
            "required": [
              "enabled"
            ],
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "True only for a key with the `audit:run` scope."
              },
              "credits_per_audit": {
                "type": "integer"
              },
              "daily_cap": {
                "type": "integer"
              },
              "audits_today": {
                "type": "integer"
              },
              "remaining_today": {
                "type": "integer"
              },
              "credits_remaining": {
                "type": "integer"
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Prose docs, authentication and worked examples",
    "url": "https://tryrankwise.com/api-docs"
  }
}