{
  "openapi": "3.1.0",
  "info": {
    "title": "Seolyticize API",
    "version": "1",
    "description": "Every Seolyticize tool, callable over REST with an API key as a bearer token. The same tools are served over the Model Context Protocol at /api/mcp. Keys are rate limited per key; every response carries X-RateLimit-* headers and a refusal carries Retry-After.\n\nArguments follow one set of conventions on every tool, translated into each tool's own names: target for a domain, URL or site; market (us-en, en-US), country (any ISO form) and language for location and language codes; keywords as strings or {keyword} objects; cursor (from meta.nextCursor) for paging; from/to or days for dates; crawlId latest or previous. Every paid tool takes maxCostMicros (refused at $0 when its quote is over) and dryRun (returns the quote, buys nothing). Error codes: GET /api/v1/errors."
  },
  "servers": [
    {
      "url": "https://seolyticize.com"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Client",
      "description": "Tools that address one client, named by clientId."
    },
    {
      "name": "Agency",
      "description": "Tools answered for the agency as a whole."
    }
  ],
  "paths": {
    "/api/v1/tools": {
      "get": {
        "operationId": "listTools",
        "summary": "List the tools this key may call",
        "description": "Every tool the presented key's role permits, with its input as JSON Schema. Generated from the same registry that runs the calls, so it cannot describe a tool differently from how it behaves.",
        "responses": {
          "200": {
            "description": "The catalogue as this key sees it.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "tools"
                  ],
                  "properties": {
                    "tools": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ToolDescriptor"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_clients": {
      "post": {
        "operationId": "list_clients",
        "summary": "List clients",
        "description": "Lists every client the caller can access, each with its site domains. Use this first when a request names a client by name or domain rather than id; domain narrows it to the client whose site is on that domain (www. and the scheme are ignored), which is how a provisioning script checks whether a site is onboarded already.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListClientsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_rank_summary": {
      "post": {
        "operationId": "get_rank_summary",
        "summary": "Get rank summary",
        "description": "How many tracked keywords improved, declined or held for a client, with the average position. Answers 'are rankings getting better'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRankSummaryInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_share_of_voice": {
      "post": {
        "operationId": "get_share_of_voice",
        "summary": "Get share of voice",
        "description": "The client's share of available search clicks across its tracked keywords, alongside competitors. Answers 'how much of the market do we hold'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetShareOfVoiceInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_panel_reach": {
      "post": {
        "operationId": "get_panel_reach",
        "summary": "Get panel reach",
        "description": "How many panel members visited given hosts over a period, and how often. Answers 'what did real people actually do', as far as the panel saw. Returns the panelist count alongside the visits so a thin panel is visibly thin rather than quietly wrong.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPanelReachInput"
              },
              "example": {
                "hosts": [
                  "example"
                ],
                "from": "examplexxx",
                "to": "examplexxx"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_urls": {
      "post": {
        "operationId": "submit_urls",
        "summary": "Submit URLs for crawling",
        "description": "Adds addresses to the crawl frontier for a client. Only accepts addresses on a site the agency manages — anything else is refused and named. dryRun: true adds nothing and returns wouldSubmit (the addresses as they would be queued), refused, and the quote. Answers 'crawl these pages I found'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitUrlsInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_recent_alerts": {
      "post": {
        "operationId": "list_recent_alerts",
        "summary": "List recent alerts",
        "description": "Alerts raised for a client since a given time, newest first. Lists what has fired, for anything watching — a chat channel, an automation, a status board.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListRecentAlertsInput"
              },
              "example": {
                "clientId": "client_123",
                "since": "examplexxx"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_difficulty": {
      "post": {
        "operationId": "get_keyword_difficulty",
        "summary": "Get keyword difficulty",
        "description": "How hard the first page looks for given keywords, scored from how many domains link to the pages already ranking there. Answers 'is this term worth going after'. Null where too few results have link data to judge.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordDifficultyInput"
              },
              "example": {
                "clientId": "client_123",
                "keywordIds": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_gap": {
      "post": {
        "operationId": "get_keyword_gap",
        "summary": "Get keyword gap",
        "description": "Keywords competitors rank for that the client does not, sized by the clicks available — from the client's own tracked captures, so free. For any domains and every keyword they rank for, get_domain_keyword_gap reads DataForSEO's index. Answers 'which terms are we missing'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordGapInput"
              },
              "example": {
                "clientId": "client_123",
                "competitorDomains": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_content_gap": {
      "post": {
        "operationId": "get_content_gap",
        "summary": "Get content gap",
        "description": "Competitor pages that own a cluster of keywords the client does not cover. Answers 'what page should we build next' — use this rather than keyword gap when planning content.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetContentGapInput"
              },
              "example": {
                "clientId": "client_123",
                "competitorDomains": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_link_intersect": {
      "post": {
        "operationId": "get_link_intersect",
        "summary": "Get link prospects",
        "description": "Sites linking to the client's competitors but not to the client. Answers 'who should we approach for links'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLinkIntersectInput"
              },
              "example": {
                "clientId": "client_123",
                "competitorDomains": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_cannibalization": {
      "post": {
        "operationId": "get_cannibalization",
        "summary": "Get cannibalization",
        "description": "Keywords where several of the client's own pages compete in the same result, each with the page the keyword registry says owns it (owner, null when unregistered) and the page that should win (shouldOwn: the registered owner, else the best-placed page). Answers 'where are we competing with ourselves' and 'which page should own this query'. set_keyword_owners registers owners.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCannibalizationInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_content_decay": {
      "post": {
        "operationId": "get_content_decay",
        "summary": "Get decaying content",
        "description": "Pages losing the traffic they used to earn, over consecutive periods. Answers 'what should we refresh'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetContentDecayInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_audit_summary": {
      "post": {
        "operationId": "get_audit_summary",
        "summary": "Get site audit summary",
        "description": "Technical issues one crawl found, grouped by rule: each with its name, severity, category, how many pages it affects and howToFix. Answers 'what is broken on the site'. crawlId defaults to the latest completed crawl. Then list_issue_pages shows which pages an issue is on. indexableOnly (default true) leaves out findings on pages search engines will not index as themselves — noindexed, not answering 200, or canonicalised elsewhere — except the findings that explain why; pass false to see everything. Findings accepted as intentional (accept_issue) are taken out of the counts and listed apart in accepted, each with its reason; with path owners set (set_path_owners), each issue says how its pages split between owners (owners) and byOwner totals them.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAuditSummaryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_issue_pages": {
      "post": {
        "operationId": "list_issue_pages",
        "summary": "List the pages an issue is on",
        "description": "Lists the pages where one crawl issue was found, with the message for each page, so they can be fixed. Answers 'which pages have missing titles' or 'where are the broken links'. ruleId comes from get_audit_summary or list_crawl_issues; crawlId defaults to the latest completed crawl. Paged: limit (up to 500) and offset; total is the whole count. indexableOnly (default true) leaves out findings on pages search engines will not index as themselves — noindexed, not answering 200, or canonicalised elsewhere — except the findings that explain why; pass false to see everything. Each page carries its path owner (owner, from set_path_owners) and, when accept_issue covers it, accepted with the reason. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListIssuePagesInput"
              },
              "example": {
                "clientId": "client_123",
                "ruleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_page_issues": {
      "post": {
        "operationId": "get_page_issues",
        "summary": "Get every issue on one page",
        "description": "Lists every issue a crawl found on one page, with severity, message and howToFix. Answers 'what is wrong with this page' and, after a fix and a new crawl, 'is it fixed'. crawlId defaults to the latest completed crawl. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPageIssuesInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility": {
      "post": {
        "operationId": "get_ai_visibility",
        "summary": "Get AI assistant visibility",
        "description": "How often the client's brand appears in AI assistant answers versus competitors, and what kind of pages those answers were built from. Answers 'are we visible in ChatGPT, Copilot, Gemini and Claude' and 'what do we have to be on to get cited'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/batch_domain_metrics": {
      "post": {
        "operationId": "batch_domain_metrics",
        "summary": "Look up domains in bulk",
        "description": "Authority, keywords, traffic and referring domains for any list of domains, managed or not. Answers 'how strong is this site' for competitors and prospects.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchDomainMetricsInput"
              },
              "example": {
                "domains": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/page_vitals": {
      "post": {
        "operationId": "page_vitals",
        "summary": "How a page performs for real visitors",
        "description": "Largest Contentful Paint, Interaction to Next Paint and Cumulative Layout Shift for one address, from the Chrome UX Report. Answers 'is this page fast enough for real visitors' with field data over a trailing 28 days, which is what Google ranks on rather than a lab score.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PageVitalsInput"
              },
              "example": {
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/page_headers": {
      "post": {
        "operationId": "page_headers",
        "summary": "What the server actually returned",
        "description": "Status code, redirect chain, content type and the headers that decide indexing for one address. Answers 'why is this page not in the index' when the markup looks fine — an X-Robots-Tag noindex is invisible to anything reading the page.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PageHeadersInput"
              },
              "example": {
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_demand": {
      "post": {
        "operationId": "get_search_demand",
        "summary": "What the panel saw people search for",
        "description": "How many people in the panel searched a term, and how often, in one market. Answers 'do real people actually search this' — a reading from people rather than a vendor's model. Returns nothing at all when too few people searched it, because a term seen by two panelists is those two people rather than a measurement.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchDemandInput"
              },
              "example": {
                "query": "example",
                "market": "example",
                "since": "examplexxx"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_click_curve": {
      "post": {
        "operationId": "get_click_curve",
        "summary": "How clicks fall away down a results page",
        "description": "The share of clicks each position took, as the panel observed it — for one query, or across a whole market. Answers 'what is a position actually worth here' with a measurement rather than a published average. Positions too few people clicked are withheld, so the shares deliberately do not add up to one: the rest of the page is unmeasured, not empty.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetClickCurveInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_top_searches": {
      "post": {
        "operationId": "get_top_searches",
        "summary": "The terms the panel searched most",
        "description": "What a market actually searched for over a period, most-searched first, counted by distinct people rather than by events. Answers 'what is being looked for right now' for keyword discovery, without a vendor's list in between. Terms below the reporting floor never appear.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTopSearchesInput"
              },
              "example": {
                "market": "example",
                "since": "examplexxx"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/page_lab": {
      "post": {
        "operationId": "page_lab",
        "summary": "How a page scores in one synthetic run",
        "description": "Lighthouse performance, SEO, accessibility and best-practices scores for one address, from PageSpeed Insights. Answers 'what is slow or wrong on this page' with a reproducible lab run, including for pages too quiet for field data. diagnostics says where the time went — the LCP element and its subparts (TTFB, resource load delay, resource load duration, element render delay), DOM size, long tasks, main-thread work, script execution, render-blocking requests, unused JavaScript and CSS, third parties — and fixes ranks the findings by estimated saving. This is not what real visitors experienced — use page_vitals for that, and say which is which when reporting both. There is no interaction metric here: a synthetic run interacts with nothing.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PageLabInput"
              },
              "example": {
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_entity_pageviews": {
      "post": {
        "operationId": "get_entity_pageviews",
        "summary": "How many people looked a brand or topic up",
        "description": "Wikipedia article views for a brand or topic over a period, daily or monthly. Answers 'is interest in this name growing' with a complete count published by Wikimedia rather than a vendor's model or a panel sample. Returns nothing at all when Wikipedia has no article, which is the case for most small brands — and says which article it counted, because the closest article is not always the brand's own.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetEntityPageviewsInput"
              },
              "example": {
                "entity": "example",
                "from": "20261001",
                "to": "20261001"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_indexnow": {
      "post": {
        "operationId": "submit_indexnow",
        "summary": "Tell search engines a page changed",
        "description": "Submits changed addresses to IndexNow, which Bing, Yandex, Seznam and Naver share. Google does not take part. Only accepts addresses on a site the agency manages — anything else is refused and named. Answers 'we have just republished these pages, tell the engines'. Refuses entirely until the client's key file has been published and checked. dryRun: true sends nothing and returns wouldSubmit (empty when blocked says the real call would not send), refused, and the quote.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitIndexnowInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_domain_facts": {
      "post": {
        "operationId": "get_domain_facts",
        "summary": "What the open web says about a domain",
        "description": "Registration date and registrar from the registry, position on the Tranco top-sites list, when the Internet Archive first captured it, and the subdomains its certificates have announced, plus topicShift: the homepage's title and description as first archived against today's, crossed with the registration date, as a risk level (high: a different topic on a domain registered again after the archive first saw it, registered recently, or registered five or more years ago — the expired-domain abuse pattern; medium: a changed topic on a registration two to five years old; unknown when either page could not be read; a heuristic). Answers 'how old and how big is this, and what else is on it' and 'was this domain bought and repurposed' for any domain, free and without touching a vendor. Each figure is absent far more often than present, and an absence is never a zero: no registry record, not in the top million, never archived.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDomainFactsInput"
              },
              "example": {
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/keyword_explorer": {
      "post": {
        "operationId": "keyword_explorer",
        "summary": "Explore keyword ideas with filters",
        "description": "Expands a seed term into keyword ideas, suggestions, related terms or questions, then filters, sorts and pages them: include and exclude words, volume, difficulty, cost per click and word-count ranges, questions only, search intent, and result-page features. Answers 'which terms around this topic are worth going after'. The expansion is bought once per seed, mode and market; every later filter on the same seed is free. Rows a filter cannot judge because the number is unknown are left out and counted in unknownExcluded rather than treated as zero. Set format to csv for every matching row as a CSV file.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordExplorerInput"
              },
              "example": {
                "clientId": "client_123",
                "seed": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/serp_overview": {
      "post": {
        "operationId": "serp_overview",
        "summary": "Who is on the first page for a keyword",
        "description": "The current top ten organic results for a keyword, each with domain authority, referring domains, the estimated organic traffic of that page, links into the page where counted, and every feature on the results page — plus why the keyword's difficulty is what it is. Answers 'could we get onto that page, and who would we have to beat'. Read from a recent capture when one is held, bought otherwise. Each figure says where it came from (our link graph or the vendor; panel or published click curve), and anything unknown is null, never zero.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SerpOverviewInput"
              },
              "example": {
                "clientId": "client_123",
                "term": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/keyword_traffic_potential": {
      "post": {
        "operationId": "keyword_traffic_potential",
        "summary": "What ranking first for a keyword is worth",
        "description": "Traffic potential and parent topic for a keyword: the estimated monthly organic traffic of the page ranking first, summed across every keyword that page ranks for, and that page's highest-volume keyword. Answers 'how much traffic is this keyword really worth' and 'what topic should the page be about' — a keyword's own volume undersells it. Estimated through the measured click curve and labelled with its source. Null when the leader's rankings are unknown, never zero. May buy the results page and the leader's ranked keywords when the archive holds neither.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/KeywordTrafficPotentialInput"
              },
              "example": {
                "clientId": "client_123",
                "term": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/striking_distance": {
      "post": {
        "operationId": "striking_distance",
        "summary": "Queries just off the top, by page",
        "description": "Search Console queries where the client already ranks around positions four to twenty with meaningful impressions, grouped by the page that ranks. Each has the expected click-through rate now and at the top three from the measured click curve, the extra monthly clicks a move to third (and to first) would bring, and an opportunity score that favours queries nearest the top. Answers 'which existing pages should we improve first'. Read from stored console data; buys nothing. Null when the client has no site configured.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StrikingDistanceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/explain_keyword_difficulty": {
      "post": {
        "operationId": "explain_keyword_difficulty",
        "summary": "Why a keyword is as hard as it is",
        "description": "Which first-page results set a keyword's difficulty score and which make it harder than the score suggests: each result's referring domains and role (sets the median, above it, below it, or unscored for lack of link data), the strongest and weakest result, the domain authority beside each, and a one-paragraph summary. Answers 'why is this keyword a 47' so the number can be checked rather than trusted. Read from the archive and our link graph; buys nothing, and a keyword never captured is reported unscored.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExplainKeywordDifficultyInput"
              },
              "example": {
                "term": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_keyword_lists": {
      "post": {
        "operationId": "list_keyword_lists",
        "summary": "List keyword lists",
        "description": "The keyword lists the caller can see, with how many keywords each holds — one client's, or every list the caller may reach when no client is named. Answers 'where did we save those keywords'. The agency's own lists, which belong to no client, are only visible to people who can see every client.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListKeywordListsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_keyword_list": {
      "post": {
        "operationId": "create_keyword_list",
        "summary": "Create a keyword list",
        "description": "Creates a named keyword list, for one client or for the agency, optionally with its first keywords. Answers 'keep these keywords somewhere'. A keyword is its words plus a location code, language and engine; the same words for another country are a different keyword. Each keyword may carry the metrics another tool already returned for it (volume, difficulty, CPC, intent, SERP features), stored with their read time so the list starts with numbers without buying them twice. Returns created: false with the reason when the name is already taken, rather than failing.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKeywordListInput"
              },
              "example": {
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_keywords_to_list": {
      "post": {
        "operationId": "add_keywords_to_list",
        "summary": "Add keywords to a list",
        "description": "Adds keywords to an existing list. Keywords already on it are counted as already present and otherwise left alone, except that metrics passed with them replace the fields given. Answers 'save these to that list'. Each keyword may carry the metrics keyword_explorer or get_keyword_metrics already returned (volume, difficulty, CPC in micro-USD, intent, SERP features); they are stored with their read time, so refresh_keyword_list_metrics need not buy them again. Location code defaults to 2840 (United States), language to en, engine to google.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddKeywordsToListInput"
              },
              "example": {
                "listId": "example",
                "keywords": [
                  {
                    "term": "carrier lookup"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_keywords_from_list": {
      "post": {
        "operationId": "remove_keywords_from_list",
        "summary": "Remove keywords from a list",
        "description": "Removes keywords from a list by keyword id. Tracked keywords that came from the list stay tracked. Answers 'take these off that list'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveKeywordsFromListInput"
              },
              "example": {
                "listId": "example",
                "keywordIds": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/tag_keywords": {
      "post": {
        "operationId": "tag_keywords",
        "summary": "Tag tracked keywords",
        "description": "Puts tags on a tracker's keywords, or takes them off with remove: true. Answers 'label these as our brand terms'. Tags are case-insensitive labels such as 'brand' or 'money terms' that the tracker view filters by. Keywords the tracker does not track are returned in notTracked rather than tagged.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagKeywordsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "keywordIds": [
                  "example"
                ],
                "tags": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_rank_history": {
      "post": {
        "operationId": "get_rank_history",
        "summary": "Get rank history",
        "description": "Day-by-day positions for a tracker's keywords, each day with the page that ranked and the search features on the page — and which of those the client held. Answers 'how has this keyword moved, and with which page'. Mobile and desktop are separate series. A null position means the page was read and the client was not on it; a missing day means nobody read the page that day. Neither is a zero.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRankHistoryInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_features": {
      "post": {
        "operationId": "get_serp_features",
        "summary": "Get SERP features",
        "description": "Which search features — featured snippet, AI Overview, local pack, video, People Also Ask and others — appeared on each tracked keyword's latest page, and which the client holds, with totals per feature. Answers 'which snippets and overviews do we own'. imagePresence covers image results across every keyword the client ranks for: how many ranking pages carry an image pack, how many show a client image, and the keywords where it ranks but has no image in the pack (best position first) — 'where should we be in image results'. Features are null for a capture whose source did not report them, which is not the same as a page with none.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpFeaturesInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_position_distribution": {
      "post": {
        "operationId": "get_position_distribution",
        "summary": "Get position distribution",
        "description": "How a tracker's keywords spread across positions 1-3, 4-10, 11-20, 21-50 and 51-100 each day, with average position and visibility, per device. Answers 'how many keywords are on page one, and is that growing'. Keywords read and not found are counted as not ranking, apart from every band; keywords not read that day are counted as not captured. The average is over ranking keywords only.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPositionDistributionInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_url_swaps": {
      "post": {
        "operationId": "get_url_swaps",
        "summary": "Get ranking URL swaps",
        "description": "Tracked keywords whose ranking page changed over a period — which page replaced which, when, and at what positions — flagging pages that take turns, and any keyword where several of the client's pages rank at once right now. Answers 'which keywords have two of our pages fighting over them'. Use it alongside get_cannibalization, which looks at one snapshot rather than across time.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetUrlSwapsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_console_performance": {
      "post": {
        "operationId": "get_search_console_performance",
        "summary": "What Google Search Console measured",
        "description": "Clicks, impressions and position from the client's own Google Search Console, for one search type (web, image, video, news, discover, googleNews) over a date range, optionally filtered to one country (ISO 3166-1 alpha-3, e.g. gbr) and one device. Ask for any of the dimensions date, query, page, country and device; asking for both page and query returns the page-by-query drill-down, which has no country or device split. Answers 'what did this site actually earn in Google'. Discover and Google News have no queries and no position. Days Google is still counting are marked provisional. Returns a refusal with a reason when Search Console is not connected or a filter does not apply.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchConsolePerformanceInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/inspect_url": {
      "post": {
        "operationId": "inspect_url",
        "summary": "Ask Google what it holds for one page",
        "description": "Runs Google's URL Inspection on one address of the client's own site: whether it is indexed, Google's coverage state, when it was last crawled, Google's chosen canonical against the site's own, mobile usability (deprecated by Google and often absent) and rich results detected. Answers 'is this page in Google, and if not why'. Spends one of the property's 2,000 daily inspections; refuses addresses that are not on a site the agency manages for this client, and says so when the day's allowance is used.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InspectUrlInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_index_coverage": {
      "post": {
        "operationId": "get_index_coverage",
        "summary": "Which of the client's pages Google has indexed",
        "description": "The newest URL Inspection verdict for every page of the client's site that has been inspected, grouped by verdict and by Google's coverage state, with pages whose Google-chosen canonical differs from their own. Answers 'how much of this site is in Google, and what is keeping the rest out'. Covers inspected pages only — Search Console's own indexing report has no API — and says how many that is and how many are still queued.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetIndexCoverageInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/sync_search_console": {
      "post": {
        "operationId": "sync_search_console",
        "summary": "Collect Search Console data now",
        "description": "Collects the latest days from Search Console now instead of waiting for the nightly sync — and the sixteen-month history too if it is still owed. Runs in the background for a minute or two; read the data with the Search Console tools afterwards. Returns the previous sync's time and note: a note saying Google reported no search data means the property had no impressions on those days (a new or barely visible site), not a broken connection. Answers 'pull our Search Console data now'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncSearchConsoleInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_sitemaps": {
      "post": {
        "operationId": "list_sitemaps",
        "summary": "The sitemaps each search engine knows about",
        "description": "The client's sitemaps as Google, Bing and Yandex each report them: submitted URL counts, errors and warnings, when each was last read. Answers 'are our sitemaps being read, and are they broken'. Google no longer reports how many of a sitemap's URLs are indexed, so that figure is always null; instead, of the pages inspected, how many came from each sitemap and passed. Each engine's part is separately present, refused or failed.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListSitemapsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_sitemap": {
      "post": {
        "operationId": "submit_sitemap",
        "summary": "Submit a sitemap to Google",
        "description": "Submits a sitemap address to the client's Google Search Console property. Answers 'tell Google about this sitemap'. Refuses an address that is not on a site the agency manages for this client, Connected by the agency's Google account (verify_site, or the account added as a user), it submits directly — no further permission; Google itself refuses if that account is only a Restricted user, and the refusal says what to change. Connected by someone's Google sign-in, it needs sitemap management allowed separately (a second Google permission, never assumed from the read-only one).",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitSitemapInput"
              },
              "example": {
                "clientId": "client_123",
                "sitemapUrl": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_sitemap": {
      "post": {
        "operationId": "delete_sitemap",
        "summary": "Remove a sitemap from Google",
        "description": "Removes a sitemap from the client's Google Search Console property. Answers 'stop Google reading this old sitemap'. Same refusals as submit_sitemap: only addresses on a site the agency manages, and only once sitemap management has been allowed.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteSitemapInput"
              },
              "example": {
                "clientId": "client_123",
                "sitemapUrl": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_bing_performance": {
      "post": {
        "operationId": "get_bing_performance",
        "summary": "What Bing Webmaster Tools reports",
        "description": "The client's site as Bing reports it, on the agency's Webmaster Tools key: daily clicks and impressions, page and query stats, crawl stats (pages crawled, in index, errors by status), crawl issues per URL, sitemaps and feeds, and the URL submission quota. Answers 'how is this site doing in Bing'. These are Bing's numbers about Bing's searchers and must never be added to Google's. Each part is separately present or failed; connected is false when the agency has no Bing key.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBingPerformanceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_performance": {
      "post": {
        "operationId": "get_yandex_performance",
        "summary": "What Yandex Webmaster reports",
        "description": "The client's site as Yandex Webmaster reports it: site quality index, searchable and excluded pages, problems by severity, popular search queries with impressions, clicks and position, indexing history by HTTP status, sitemaps, and the recrawl queue with its quota. Answers 'how is this site doing in Yandex'. configured is false when this deployment has no Yandex app, and connected is false until the client's site owner has granted access.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexPerformanceInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_baidu_urls": {
      "post": {
        "operationId": "submit_baidu_urls",
        "summary": "Push pages to Baidu",
        "description": "Pushes addresses on the client's own site to Baidu through Ziyuan's link submission, the only API Baidu offers a site owner. Answers 'tell Baidu about these pages'. Returns how many Baidu accepted and how many more it will take today — Baidu reports its allowance only in reply to a push. Refuses addresses not on the client's registered site, and refuses entirely when no Baidu token has been saved.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitBaiduUrlsInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_yandex_recrawl": {
      "post": {
        "operationId": "submit_yandex_recrawl",
        "summary": "Ask Yandex to recrawl pages",
        "description": "Asks Yandex Webmaster to recrawl pages of the client's verified Yandex host, one task per page. Answers 'get Yandex to look at these pages again'. Returns the task id Yandex gave each queued page; get_yandex_performance shows the queue and the day's remaining quota. Refuses addresses not on the verified host (Yandex treats www and the bare domain as different hosts). The first quota refusal stops the rest, which come back as not sent.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitYandexRecrawlInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/export_search_console_data": {
      "post": {
        "operationId": "export_search_console_data",
        "summary": "Export Search Console queries or pages as CSV",
        "description": "Google Search Console queries or pages (dimension) for a search type, date range, and optionally one country and device, as CSV with clicks, impressions, click-through rate and average position — up to 5,000 rows. Returns filename, rows and csv. Cells a spreadsheet would run as formulas are neutralised. Answers 'give me the query data in a spreadsheet'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportSearchConsoleDataInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_baidu_token": {
      "post": {
        "operationId": "save_baidu_token",
        "summary": "Save the client's Baidu push token",
        "description": "Saves the link-push token from Baidu Ziyuan (ziyuan.baidu.com, link submission page) for the client's site, so submit_baidu_urls can push pages. Answers 'connect Baidu for this client'. The site must be the client's own registered site; the token is stored encrypted and never returned. Replaces any token already saved.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveBaiduTokenInput"
              },
              "example": {
                "clientId": "client_123",
                "siteUrl": "https://example.com/page",
                "token": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_console_hourly": {
      "post": {
        "operationId": "get_search_console_hourly",
        "summary": "Search Console clicks and impressions by the hour",
        "description": "Clicks, impressions and position from the client's Google Search Console hour by hour over the last 1–10 days (Google keeps hours for ten days only), read live, for one search type. Hours are Pacific time, as Search Console keys them; the newest are partial while Google counts and are marked so. Answers 'did traffic dip right after the release' and 'is the core update hitting us today'. Free; returns a refusal when Search Console is not connected.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchConsoleHourlyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_client_brief": {
      "post": {
        "operationId": "get_client_brief",
        "summary": "Read the client brief",
        "description": "Reads what the agency knows about a client: overview, current goal, positioning, audience, writing voice, competitors, key pages, custom sections, and the research log (newest first). Answers 'what do we know about this client'. Read it before researching, writing or reporting for a client, so the work matches the business and builds on earlier findings. Fields nobody has written are null, not empty. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetClientBriefInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_client_brief": {
      "post": {
        "operationId": "update_client_brief",
        "summary": "Update the client brief",
        "description": "Changes the client brief that every teammate and agent reads. Answers 'remember this about the client'. Set fields (overview, goal, positioning, audience, voice; null or empty clears one, fields left out are untouched); add entries (kind competitor, key_page, section or research, each with a title and optional body and url); edit entries by id; remove entries by id (unknown ids are ignored); replace the brand terms (brandTerms) that split branded from non-branded search. Applied in that order, so removing an old competitor and adding its replacement in one call works. Record a research entry when you finish a piece of work whose conclusions the next one should start from; the 50 newest research notes are kept. Returns the brief as it now stands. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBriefInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_client_brief": {
      "post": {
        "operationId": "draft_client_brief",
        "summary": "Draft the client brief from their website",
        "description": "Reads the client's home page and up to four of its about, services, product or pricing pages, and drafts the brief's overview, positioning, audience and voice, plus the key pages with what each is for. Answers 'set up this client's brief'. Nothing is saved: show the draft to the user, correct it, then save what is right with update_client_brief — alreadyWritten lists fields the brief already has, which should not be overwritten without asking. Says 'Not stated on the site.' where the pages are silent, and never names competitors. A paid Claude call charged to the client's budget (costMicros reports what it cost).",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftClientBriefInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_written_reports": {
      "post": {
        "operationId": "list_written_reports",
        "summary": "List written reports",
        "description": "Lists the written reports saved for a client, newest change first: id, title, a plain-text summary, who wrote and last changed it, and whether it is shared. Answers 'what reports have we written for this client'. Call it before save_written_report to find a report to replace rather than writing a duplicate. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListWrittenReportsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_written_report": {
      "post": {
        "operationId": "get_written_report",
        "summary": "Read a written report",
        "description": "Reads one written report: its Markdown, the rendered HTML, its summary, who wrote it, and its public shareUrl (null while private). Answers 'show me that report'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetWrittenReportInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_written_report": {
      "post": {
        "operationId": "save_written_report",
        "summary": "Save a written report",
        "description": "Saves a finished report to a client, where everyone on the account can read and print it. Answers 'save this report for the client'. Write it in Markdown (headings, lists, tables, links); raw HTML is shown as text, not run. Without reportId a new report is created; with one, that report's title and text are replaced and its share link, if any, keeps working. Name templateId when it was written to a report template. New reports are private — use set_report_sharing only when the user asks for a link. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveWrittenReportInput"
              },
              "example": {
                "clientId": "client_123",
                "title": "example",
                "markdown": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_written_report": {
      "post": {
        "operationId": "delete_written_report",
        "summary": "Delete a written report",
        "description": "Permanently deletes one written report; its share link stops working at once. Answers 'remove that report'. Does not touch data reports, templates or anything else. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteWrittenReportInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_report_sharing": {
      "post": {
        "operationId": "set_report_sharing",
        "summary": "Share a written report by link",
        "description": "Turns a written report's public link on or off. Answers 'give me a link I can send the client'. Anyone holding the link can read the report without an account, so only turn it on when the user explicitly asks. Turning it on for a report already shared returns the same link; turning it off breaks the link immediately, and sharing again later makes a new one. The page carries a preview card for Slack, email and social networks. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetReportSharingInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example",
                "shared": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_report_templates": {
      "post": {
        "operationId": "list_report_templates",
        "summary": "List report templates",
        "description": "Lists the report templates that apply: the agency's own, plus the client's when clientId is given — each with its audience, sections in order with guidance, tone and sign-off. Answers 'how do we usually write this report'. Follow a template's sections and tone when writing a report it fits, and name it in save_written_report. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListReportTemplatesInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_report_template": {
      "post": {
        "operationId": "save_report_template",
        "summary": "Save a report template",
        "description": "Saves a reusable brief for a kind of report: a name, who it is for, sections in order (each with a line on what goes under it), tone and sign-off. Answers 'make this our monthly report format'. Without clientId it is agency-wide, which only someone who sees every client may change; with one it is that client's own. Without templateId a new template is made; with one, it is replaced. Only save a template when the user asks for one — a one-off report needs none. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveReportTemplateInput"
              },
              "example": {
                "name": "example",
                "sections": [
                  {
                    "heading": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_report_template": {
      "post": {
        "operationId": "delete_report_template",
        "summary": "Delete a report template",
        "description": "Permanently deletes one report template. Answers 'we no longer use that format'. Reports written to it are kept. Call list_report_templates to find its id. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteReportTemplateInput"
              },
              "example": {
                "templateId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_overview": {
      "post": {
        "operationId": "get_ga4_overview",
        "summary": "Is organic traffic growing (GA4)",
        "description": "Top-line sessions, users, engaged sessions, engagement rate, key events, transactions and revenue for organic search (channel \"all\" for every channel), against the previous period, plus a daily sessions and key-events line. Answers 'is organic traffic improving'. total holds the figures. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4OverviewInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_traffic_acquisition": {
      "post": {
        "operationId": "get_ga4_traffic_acquisition",
        "summary": "Where traffic comes from (GA4)",
        "description": "Sessions, users, engaged sessions, key events, transactions and revenue by channel group, source/medium or campaign (groupBy), against the previous period. Answers 'which channels grew or fell'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4TrafficAcquisitionInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_landing_pages": {
      "post": {
        "operationId": "get_ga4_landing_pages",
        "summary": "What landing pages did (GA4)",
        "description": "Sessions, engaged sessions, engagement rate, key events, transactions and revenue by landing page, organic search by default. Answers 'which pages search sends people to, and what they did there'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4LandingPagesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_page_performance": {
      "post": {
        "operationId": "get_ga4_page_performance",
        "summary": "Page views and engagement (GA4)",
        "description": "Views, users, total engagement time in seconds and key events by page path, organic search by default (channel \"all\" for every channel). Answers 'which pages hold attention'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4PagePerformanceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_key_events": {
      "post": {
        "operationId": "get_ga4_key_events",
        "summary": "Key events (GA4)",
        "description": "Counts of the property's key events (what used to be conversions) by event name, or by the organic landing page that led to them (by \"landingPage\"). Answers 'what are visitors converting on'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4KeyEventsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_ecommerce": {
      "post": {
        "operationId": "get_ga4_ecommerce",
        "summary": "Shop performance (GA4)",
        "description": "Item views, add-to-carts, purchases and item revenue by item, or transactions and purchase revenue by organic landing page (by \"landingPage\"). activity is \"detected\" or \"none\" — none means the property sends no ecommerce events for the period, not that nothing sold. Answers 'what is selling, and from which pages'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4EcommerceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_site_search": {
      "post": {
        "operationId": "get_ga4_site_search",
        "summary": "What visitors search for on the site (GA4)",
        "description": "Terms people typed into the site's own search, with searches and users. measured is false when the property records no site search (enhanced measurement off, or no search box). Answers 'what are people looking for that the site does not surface'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4SiteSearchInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_audience": {
      "post": {
        "operationId": "get_ga4_audience",
        "summary": "Who arrives (GA4)",
        "description": "Users, sessions, engaged sessions and key events by device, country, or new versus returning (by), organic search by default. Answers 'is mobile or desktop converting, which countries'. Rows carry key, current (metrics by name) and previous (null when compare is false, metrics null where that period had no row). Also period, previousPeriod, currency, thresholded and folded. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4AudienceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ga4_measurement_health": {
      "post": {
        "operationId": "get_ga4_measurement_health",
        "summary": "Is the property measuring properly (GA4)",
        "description": "Checks the connected property's setup: web data streams and measurement ids, enhanced measurement per stream (scrolls, outbound clicks, site search, forms, downloads), marked key events, custom dimensions and metrics, the last day with sessions, and Consent Mode v2 on each stream's site (an inline gtag consent default naming ad_user_data and ad_personalization; a consent platform or Tag Manager that may set it out of sight is named, not marked missing). findings lists problems, warnings and notes in plain words; a part that could not be read is reported as unread, not as fine. Answers 'can we trust this client's Analytics'. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGa4MeasurementHealthInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_opportunities": {
      "post": {
        "operationId": "get_search_opportunities",
        "summary": "Pages worth an edit first (Search Console × GA4)",
        "description": "Joins Search Console pages ranking around positions 4–20 with what their organic visitors do in GA4 over the same window, and ranks them by projected revenue, then projected key events, then extra clicks. Each row: page, extraClicks (from the click curve at third place), its top queries, the page's organic sessions, key event rate and revenue per session (analytics null where GA4 has no row for it — unknown, not worthless), and the projections. searchConsole is false when the client has no site or console data. Answers 'which page should we improve first'. Refuses with a sentence when the client has not connected a GA4 property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchOpportunitiesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_web_analytics_setup": {
      "post": {
        "operationId": "get_web_analytics_setup",
        "summary": "Is web analytics installed",
        "description": "Whether Seolyticize's own cookieless web analytics is set up for a client, with the one-line tracking snippet to install (it sends the page's origin and path and never its query string, except utm_* campaign tags, nor its fragment), the site key, collectUrl for sending events from your own code (get_collect_contract has the fields and limits), the hostnames allowed to report, and lastEventAt (null until the first visit is recorded). Answers 'is the tracking script installed' and 'what snippet do I add to the site'. configured is false when no snippet has been created yet. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetWebAnalyticsSetupInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_collect_contract": {
      "post": {
        "operationId": "get_collect_contract",
        "summary": "How events are collected",
        "description": "The collect endpoint's contract, for a site or app that sends events itself instead of using a.js: the URL, the fields, the limits (body bytes, u length, event name, props), the rate limit, when a visit ends, how single-page apps are counted (no server-side dedupe), what is dropped and how each refusal answers. Answers 'can I send pageviews from my own code' and 'is a repeat pageview counted'. Same for every client. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCollectContractInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_up_web_analytics": {
      "post": {
        "operationId": "set_up_web_analytics",
        "summary": "Set up web analytics",
        "description": "Creates a client's cookieless web analytics, or changes which hostnames may report to it, and returns the same shape as get_web_analytics_setup: the one-line tracking snippet to add to every page, the allowed hostnames and lastEventAt. Answers 'install tracking on this site'. Without hostnames it allows the client's own domain and its www form; with hostnames, those replace the list (up to 20; a visit from any other hostname is ignored, so add staging or extra domains here). Safe to repeat: an existing setup keeps its snippet. configured is false when the client has no site domain to default to and no hostnames were given. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetUpWebAnalyticsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_web_analytics_summary": {
      "post": {
        "operationId": "get_web_analytics_summary",
        "summary": "Site traffic summary (first-party)",
        "description": "Visitors, visits, pageviews, views per visit, bounce rate and average visit duration from Seolyticize's own web analytics, against the same span before (previous is null when that span was not fully measured), plus a daily series, realtimeVisitors in the last 30 minutes, and notes on how figures are counted. Answers 'how much traffic did the site get' for a client without GA4. Visitors are counted per day without cookies; a figure of null means not measured, not zero. Refuses with a sentence when web analytics has not been set up for the client. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetWebAnalyticsSummaryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_web_analytics_breakdown": {
      "post": {
        "operationId": "get_web_analytics_breakdown",
        "summary": "Traffic by page, source, campaign, country or device (first-party)",
        "description": "Lists the top rows of one breakdown from Seolyticize's own web analytics: pages (pageviews), entry_pages and exit_pages (visits), sources and referrers (visits; key null means direct), campaigns (visits, with detail \"source / medium\"), countries (ISO codes; null means unknown), devices, browsers, os, custom events (event count), channels (visits by channel: AI, Organic Search, Paid Search, Social, Email, Referral, Campaign, Direct), ai_sources (visits from each AI assistant: ChatGPT, Perplexity, Gemini, Copilot, Claude, Google AI Mode and others), ai_landing_pages (the pages AI assistants send visits to, detail naming the assistant) or partners (pageviews by who served the page: \"site\" for the site's own, or each partner declared with set_up_web_analytics). Each row has key, visitors and count; counts says what count counts, and totalKeys how many rows exist before the limit. Answers 'which pages and sources drive visits'. Refuses with a sentence when web analytics has not been set up for the client. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetWebAnalyticsBreakdownInput"
              },
              "example": {
                "clientId": "client_123",
                "breakdown": "pages"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_setup": {
      "post": {
        "operationId": "get_ai_visibility_setup",
        "summary": "AI visibility setup",
        "description": "Reads what is tracked for a client: the questions (with their market, topic, and whether each is branded — names a tracked brand — or neutral, worked out automatically unless overridden), the topics and the branded/neutral split, the brands looked for (which one is the client's own), the schedule (cadence, which assistants, last run, whether sentiment is judged), and which assistants this agency can ask at all and how (its own key or its proxy pool). Answers 'what are we measuring in AI assistants'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilitySetupInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_ai_visibility_setup": {
      "post": {
        "operationId": "save_ai_visibility_setup",
        "summary": "Change what AI visibility tracks",
        "description": "Adds questions (each optionally with a two-letter market, a topic, and branded true/false to override the automatic reading), regroups or reclassifies questions by id (updatePrompts: topic null to ungroup, branded null to go back to automatic), retires questions by id (past answers keep their question), and adds brands to look for (name, domain, aliases; isClient for the client's own — there should be exactly one). Questions already tracked are skipped. dryRun: true changes nothing and lists what would: the questions it would add, retire and regroup, those it would skip, and the brands it would add (with why one would be refused). Write questions the way a buyer would ask an assistant, without naming any brand; suggest_ai_prompts drafts them. Answers 'track these questions'. Free; the checks that follow are what cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveAiVisibilitySetupInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_ai_visibility_schedule": {
      "post": {
        "operationId": "set_ai_visibility_schedule",
        "summary": "Set how often AI visibility is checked",
        "description": "Sets a client's cadence (off, daily, weekly or monthly; weekly unless changed) which assistants it is checked on (engines; null or empty for every one the agency has configured), and whether each answer naming a tracked brand is also judged for sentiment (off by default; one metered Claude call per such answer, its ceiling in estimate_ai_visibility_cost as sentimentIfOnPerRunMaxMicros). Every scheduled check asks every question on every chosen assistant, so show estimate_ai_visibility_cost first. Answers 'check this daily on ChatGPT and Perplexity'. Free to set.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetAiVisibilityScheduleInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/estimate_ai_visibility_cost": {
      "post": {
        "operationId": "estimate_ai_visibility_cost",
        "summary": "What an AI visibility check costs",
        "description": "Estimates one check and a month at the current cadence: questions × assistants answers per run, and the most the Claude answers can cost (Seolyticize meters Claude; other assistants bill the agency's own accounts at their own prices, so they are counted, not priced). Answers 'how much will tracking this cost'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateAiVisibilityCostInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/run_ai_visibility_check": {
      "post": {
        "operationId": "run_ai_visibility_check",
        "summary": "Run an AI visibility check now",
        "description": "Asks every tracked question on the chosen assistants now, in the background; results arrive within minutes in get_ai_visibility_runs and get_ai_visibility_results. The schedule is unchanged. With maxCostMicros, the check is refused before it starts when its estimate is over the limit. Get the user's go-ahead first: it spends. Answers 'check it now'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunAiVisibilityCheckInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_runs": {
      "post": {
        "operationId": "get_ai_visibility_runs",
        "summary": "AI visibility checks so far",
        "description": "Lists the client's checks, newest first: when, how many answers, which assistants, and in how many the client's own brand was named (mentionRate; null when no brand is marked as the client's), and the same rate on neutral questions only (neutralMentionRate), the one branded questions cannot flatter. Answers 'when did we last check, and how did it go'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilityRunsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_results": {
      "post": {
        "operationId": "get_ai_visibility_results",
        "summary": "AI visibility results, answer by answer",
        "description": "One check (the latest unless capturedAt names one from get_ai_visibility_runs), as a row per question and assistant: the question's topic and whether it is branded, whether the client was named, where in the answer (character offset; earlier is more prominent), whether its site was cited, how the answer described it (clientSentiment positive / neutral / negative with a one-line note; null when not named or not judged), and which other brands were named, in order. summary gives mention rate, citations and sentiment overall, neutral against branded, and per topic. Filter by topic or segment. Answers 'which questions are we missing from' and 'how do assistants talk about us'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilityResultsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_answer": {
      "post": {
        "operationId": "get_ai_visibility_answer",
        "summary": "Read one AI answer in full",
        "description": "The full text one assistant gave to one question in one check, with the pages it cited, where each tracked brand appears in it, and how it described each (sentiment by brand, empty when not judged). found is false when that answer was never captured or has aged out (answers are kept 13 months). Answers 'what exactly did ChatGPT say'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilityAnswerInput"
              },
              "example": {
                "clientId": "client_123",
                "promptId": "example",
                "model": "claude",
                "capturedAt": "examplexxx"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_trend": {
      "post": {
        "operationId": "get_ai_visibility_trend",
        "summary": "Is AI visibility improving",
        "description": "The client's own mention rate over the last N days (default 28) against the N days before, overall and per assistant, counted by answer, with how many answers each side rests on. Filter by topic, or segment neutral for the rate on questions naming no brand. Answers 'are we being recommended more than last month'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilityTrendInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/export_ai_visibility_data": {
      "post": {
        "operationId": "export_ai_visibility_data",
        "summary": "Export AI visibility data",
        "description": "CSV of the last N days (default 90): include \"mentions\" for one row per answer and brand (named, position, cited), or \"answers\" for the full answer text and citations (up to 2,000 answers). Returns rows and csv. Answers 'give me the raw data for a deck'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportAiVisibilityDataInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/explore_ai_prompt": {
      "post": {
        "operationId": "explore_ai_prompt",
        "summary": "Ask assistants one question now",
        "description": "Asks one question live on the chosen assistants (claude, and any the agency has its own API key for) and returns each answer's text, citations, and — when clientId is given — which tracked brands it named. Nothing is stored; use it to see what assistants say before tracking a question, or to look up how they describe a brand. Answers 'what does ChatGPT say about this'. Claude is metered (meteredMicros); others bill the agency's own accounts.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExploreAiPromptInput"
              },
              "example": {
                "prompt": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/suggest_ai_prompts": {
      "post": {
        "operationId": "suggest_ai_prompts",
        "summary": "Suggest questions to track",
        "description": "Drafts questions worth tracking, grouped by topic, from the client brief, its brands and what is already tracked — phrased as a buyer would ask an assistant, never naming a tracked brand, never repeating a tracked question. Optionally around one topic. Nothing is saved: show them, then save the chosen ones with save_ai_visibility_setup. For questions people actually search, use keyword_explorer with mode questions. Answers 'what should we be tracking'. A metered Claude call.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuggestAiPromptsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_cited_sources": {
      "post": {
        "operationId": "get_ai_cited_sources",
        "summary": "Who owns the pages AI answers cite",
        "description": "The pages assistants cited for the client's tracked questions over the last N days (default 30), each domain classed by owner — own (the client's site), competitor (a tracked competitor's site, named), ugc (Reddit, Quora, YouTube, forums, social) or third_party (everyone else) — with each class's share of citations, each competitor's share, and the domains in order with their page type, questions, assistants and most-cited page. Counted once per answer. Filter by topic, segment or one assistant. Answers 'whose content are AI answers built from' and 'where should we get mentioned'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiCitedSourcesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_visibility_sentiment": {
      "post": {
        "operationId": "get_ai_visibility_sentiment",
        "summary": "How AI answers describe each brand",
        "description": "Sentiment over the last N days (default 30): for every tracked brand, how many answers that named it described it positively, neutrally or negatively, net score ((positive − negative) / judged) and how many were never judged; the client's split per assistant; and the latest negative and positive descriptions of the client, each with its question and assistant. Answers 'do assistants recommend us or warn people off'. Free; unjudged answers can be filled in with assess_ai_visibility_sentiment.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiVisibilitySentimentInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/assess_ai_visibility_sentiment": {
      "post": {
        "operationId": "assess_ai_visibility_sentiment",
        "summary": "Judge sentiment for answers already captured",
        "description": "Judges how each answer in one check (the latest unless capturedAt names one) describes the tracked brands it names, for answers not yet judged — those captured before sentiment was on, or when the judge was unavailable. One metered Claude call per answer, up to maxAnswers (default 50); rejudge: true judges again. Returns judged, skipped, left and costMicros. Get the user's go-ahead first: it spends. Answers 'fill in sentiment for last week's check'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssessAiVisibilitySentimentInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_markets": {
      "post": {
        "operationId": "list_markets",
        "summary": "Find a market's location code",
        "description": "Lists the countries and regions this product measures, with the location code other tools take (locationCode), the ISO code and Google's own country code. Search by name, ISO code (gb), Google code (uk) or location code (2826); an exact code wins over a name match. Answers 'what is the location code for Germany'. Only markets the product can measure honestly are listed. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListMarketsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_live_serps": {
      "post": {
        "operationId": "get_live_serps",
        "summary": "Read several results pages now",
        "description": "Reads the live results page for up to 10 keywords in one market and engine (Google by default), and returns each page's top results (position, type, domain, url, title) and the search features on it. Answers 'who ranks for these right now'. Each keyword is one purchase, made in turn; one that fails is reported and the rest still return; maxCostMicros stops before the purchase that would pass it. Quote with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLiveSerpsInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/find_serp_competitors": {
      "post": {
        "operationId": "find_serp_competitors",
        "summary": "Who competes across a keyword set",
        "description": "Finds the domains that rank across a set of keywords (up to 200) in one market: visibility (share of the keywords they hold in the top ten), keyword count, average position and estimated traffic. Answers 'who are our real search competitors for these terms'. List the client's own domain in exclude. One purchase per call.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindSerpCompetitorsInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/pin_tracked_keywords": {
      "post": {
        "operationId": "pin_tracked_keywords",
        "summary": "Pin tracked keywords to the top",
        "description": "Pins tracked keywords (by keywordId from list_tracked_keywords or get_rank_history) to the top of a tracker's table for everyone on the account, or unpins them with pinned false. Pinned keywords are listed first, in the order they were pinned. Ids not on the tracker are ignored; changed says how many moved. Answers 'keep these at the top'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PinTrackedKeywordsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "keywordIds": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_list": {
      "post": {
        "operationId": "get_keyword_list",
        "summary": "Read a keyword list",
        "description": "Every keyword in one list (by listId from list_keyword_lists): the term, its market, language and engine, its keywordId, its note and tags, and the metrics last stored for it. Answers 'what is on this list'. To filter, sort or export as CSV use query_keyword_list. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordListInput"
              },
              "example": {
                "listId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_keyword_notes": {
      "post": {
        "operationId": "set_keyword_notes",
        "summary": "Note why keywords are on a list",
        "description": "Sets notes on keywords in a list — why each is there, which page it belongs to, what was decided — by keywordId from get_keyword_list. An empty note clears it; ids not on the list are ignored and changed says how many were set. Answers 'note that this one is for the implants page'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetKeywordNotesInput"
              },
              "example": {
                "listId": "example",
                "notes": [
                  {
                    "keywordId": "example",
                    "note": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/whoami": {
      "post": {
        "operationId": "whoami",
        "summary": "Who am I connected as",
        "description": "Says who this connection is: the agency, whether it is an API key or a person, the role, every permission that role holds, the clients it can reach, and vendorBalanceUsable (false when the agency's DataForSEO balance is empty and paid calls fail, null with no key of its own or when it cannot be read). Answers 'what can this key do'. Call it first when unsure whether a task is allowed. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhoamiInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_low_ctr_queries": {
      "post": {
        "operationId": "get_low_ctr_queries",
        "summary": "Queries losing clicks to their snippet",
        "description": "Search Console queries on page one (positions 1–10) with enough impressions where far fewer people click than that position normally earns (under half the click curve's rate): actual and expected click-through rate and the clicks missed, worst first. Answers 'which titles and descriptions should we rewrite'. Check get_serp_features first — an AI overview or map pack above the result also lowers clicks. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLowCtrQueriesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_opportunities": {
      "post": {
        "operationId": "get_opportunities",
        "summary": "Everything worth working on, in one call",
        "description": "Gathers the four kinds of opportunity from stored data: strikingDistance (pages around positions 4–20 by extra clicks), lowCtr (page-one queries losing clicks to their snippet), contentDecay (pages losing clicks), and cannibalization (pages splitting one query). Each part is a section with data or an error — an unread part is not an empty one. Answers 'what should we work on for this client'. Use the individual tools for detail. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetOpportunitiesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_client": {
      "post": {
        "operationId": "get_client",
        "summary": "Get a client",
        "description": "One client's settings with its domains (client.domains), projects, sites and rank trackers (each with its frequency: daily, weekly, monthly or manual, set with update_rank_tracker), whether the paid weekly domain sweep runs (domainSweep, set with set_domain_sweep), and the analytics siteKey and collectUrl (null before set_up_web_analytics). Answers 'what is set up for this client' — use it to find tracker, project and site ids before changing anything.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetClientInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_client": {
      "post": {
        "operationId": "create_client",
        "summary": "Create a client",
        "description": "Onboards a client in one step: the client, a project, its site and a rank tracker, optionally with keywords to track. Answers 'set up a new client'. Refused when the name is taken or the plan's client or keyword allowance is used up; every tracked keyword is a paid lookup on every run.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientInput"
              },
              "example": {
                "name": "example",
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_client": {
      "post": {
        "operationId": "update_client",
        "summary": "Update a client",
        "description": "Renames a client or changes its monthly vendor spend cap (null removes the cap). Answers 'rename this client' or 'cap this client's spend'. The cap is enforced on every paid lookup from then on.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/archive_client": {
      "post": {
        "operationId": "archive_client",
        "summary": "Archive a client",
        "description": "Retires a client: it stops being tracked, crawled and reported on, stops counting against the plan, and disappears from lists. History is kept. Answers 'we no longer work with this client'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArchiveClientInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/restore_client": {
      "post": {
        "operationId": "restore_client",
        "summary": "Restore an archived client",
        "description": "Brings an archived client back: it is listed, tracked, crawled and reported on again, with its history as it was, and counts against the plan once more (refused when the plan's client limit is reached). Answers 'we're working with them again'. Safe to repeat: restored is false when the client was not archived.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestoreClientInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_projects": {
      "post": {
        "operationId": "list_projects",
        "summary": "List projects and sites",
        "description": "A client's projects with the sites under each. Lists where crawls and trackers hang from.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListProjectsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_project": {
      "post": {
        "operationId": "create_project",
        "summary": "Create a project",
        "description": "Adds a project to a client, optionally with a site domain to crawl. Answers 'add a second site or market for this client'. The domain is written like example.com.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProjectInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_site_status": {
      "post": {
        "operationId": "get_site_status",
        "summary": "Site verification and connection status",
        "description": "For a client's sites: whether the IndexNow key file has been published and verified, which Search Console properties are connected and syncing, and the latest crawl. Answers 'is this site set up and verified'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSiteStatusInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_rank_trackers": {
      "post": {
        "operationId": "list_rank_trackers",
        "summary": "List rank trackers",
        "description": "A client's rank trackers with engine, device, cadence and locale. Lists the tracker ids the ranking tools take.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListRankTrackersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_rank_tracker": {
      "post": {
        "operationId": "create_rank_tracker",
        "summary": "Create a rank tracker",
        "description": "Starts tracking a client's positions on one engine, device and locale. Answers 'track this client on Bing too' or 'track mobile separately'. Defaults to the client's first project and site domain. Engine and locale cannot be changed later — they are part of every keyword's identity — so a different market is a new tracker. A locale can be a city, county or region, not only a country: search_locations finds the code. Cadence daily, weekly, monthly or manual, at a chosen UTC hour and day; depth 10–200; match the exact host, its subdomains, or a URL prefix.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRankTrackerInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_rank_tracker": {
      "post": {
        "operationId": "update_rank_tracker",
        "summary": "Update a rank tracker",
        "description": "Renames a tracker or changes its device (desktop, mobile or both), cadence (daily, weekly, monthly, or manual — only when refresh_rankings asks), the hour and day it runs, how deep it reads (10–200 results), or what counts as the client (the exact host, every subdomain, or only a folder or page via urlPrefix). Answers 'check these weekly instead', 'track only our /blog/ pages'. Weekly costs a seventh as much, monthly a thirtieth.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRankTrackerInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_rank_tracker": {
      "post": {
        "operationId": "delete_rank_tracker",
        "summary": "Delete a rank tracker",
        "description": "Stops a tracker. Positions it already captured stay in reports; no further runs are made or charged. Answers 'stop tracking this'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteRankTrackerInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_tracked_keywords": {
      "post": {
        "operationId": "list_tracked_keywords",
        "summary": "List tracked keywords",
        "description": "The terms a tracker measures and the competitor domains it compares against. Lists what is being paid for on every run.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListTrackedKeywordsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_tracked_keywords": {
      "post": {
        "operationId": "add_tracked_keywords",
        "summary": "Track keywords",
        "description": "Adds terms to a tracker, ignoring ones already tracked. Answers 'start tracking these keywords'. Each added term is a paid lookup on every future run; refused when the plan's keyword allowance would be exceeded. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddTrackedKeywordsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "terms": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_tracked_keywords": {
      "post": {
        "operationId": "remove_tracked_keywords",
        "summary": "Stop tracking keywords",
        "description": "Removes terms from a tracker. Answers 'stop tracking these keywords'. Terms that were not tracked are ignored, so it is safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveTrackedKeywordsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "terms": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/start_crawl": {
      "post": {
        "operationId": "start_crawl",
        "summary": "Start a site audit crawl",
        "description": "Crawls the client's site now rather than waiting for the schedule. Answers 'audit the site again'. status is queued for a new crawl, or running when one already was (returned instead of starting a second). Pass the jobId it returns to wait_for_job (or poll get_crawl_status with the crawl id); read results with list_crawl_issues.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartCrawlInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_crawl_status": {
      "post": {
        "operationId": "get_crawl_status",
        "summary": "Get crawl status",
        "description": "Whether one crawl is running, complete or failed, with page and issue counts and the failure reason. Answers 'has the audit finished'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCrawlStatusInput"
              },
              "example": {
                "clientId": "client_123",
                "crawlId": "latest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_crawls": {
      "post": {
        "operationId": "list_crawls",
        "summary": "List crawls",
        "description": "A client's recent crawls of every status, newest first. Lists what the crawler has been doing, including crawls that failed.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListCrawlsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_crawl_issues": {
      "post": {
        "operationId": "list_crawl_issues",
        "summary": "List site audit issues",
        "description": "Technical issues one crawl found, by rule: its readable label, severity, category, how many pages it affects, and howToFix — concrete steps to fix it and check the fix. Lists what to fix; list_issue_pages with a ruleId gives the pages themselves, each with what was found on it. Use crawlId 'latest' for the newest completed crawl. indexableOnly (default true) leaves out findings on pages search engines will not index as themselves — noindexed, not answering 200, or canonicalised elsewhere — except the findings that explain why; pass false to see everything.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListCrawlIssuesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_reports": {
      "post": {
        "operationId": "list_reports",
        "summary": "List reports",
        "description": "A client's saved reports and their recent deliveries, including failed ones with the reason. Lists what goes out and answers 'did my report go out'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListReportsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_report": {
      "post": {
        "operationId": "create_report",
        "summary": "Create a report",
        "description": "Saves a report for a client from a list of sections; each is wired to the client's own tracker and site. Answers 'build a monthly report for this client'. Sections the client has nothing for yet are left out. Send it with send_report; schedules are set in the app.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportInput"
              },
              "example": {
                "clientId": "client_123",
                "title": "example",
                "sections": [
                  "rank-summary"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/send_report": {
      "post": {
        "operationId": "send_report",
        "summary": "Send a report now",
        "description": "Sends a saved report to its scheduled recipients now, covering the month just gone. Answers 'send the report'. Recipients come from the report's schedule and cannot be named here. Pass an idempotencyKey to make a retry land on the same send instead of emailing the client twice.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendReportInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_alert_rules": {
      "post": {
        "operationId": "list_alert_rules",
        "summary": "List alert rules",
        "description": "What a client's alerts watch for, at what threshold, and whether each is paused and can be delivered (hasDeliveryTarget false: it fires into nothing; undeliverable lists those rules with the fix). Lists the rules; list_recent_alerts lists what they fired. add_default_alerts adds the starting four.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListAlertRulesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_alert_rule": {
      "post": {
        "operationId": "create_alert_rule",
        "summary": "Create an alert rule",
        "description": "Raises an alert when a client's rankings, traffic, issues or backlinks cross a threshold, or the site goes down, and delivers it by channel. Threshold by kind: rank-drop positions fallen; traffic-drop percent lost; new-critical-issues and backlinks-lost a count; serp-features features lost (or won); competitor-new-pages new pages one tracked competitor's sitemap gained; page-changes own pages whose title, meta description, H1 or canonical changed, went noindex or 404 between the last two audits; ai-mention-drop percentage points the client's AI mention or citation rate fell from the previous check; competitor-new-keywords tracked keywords one competitor started ranking for; web-mentions new pages our crawl found naming the brand; link-velocity referring domains gained or lost in one day, far above that domain's own baseline, for the client or a tracked competitor. The watch kinds look back to their last firing (a week at most) and stay silent until there is something to compare. Channels: slack (webhookUrl, Slack's format; the default), webhook (webhookUrl, plain JSON), discord (webhookUrl, the channel's Discord webhook as Discord shows it), email (emailRecipients, up to ten) or telegram (telegramChatId, with the agency's bot from Settings). Webhooks must be https and public. With no channel and no destination, the alert goes to the agency owner's email and deliveryNote says so; a channel named without its field is refused as no_delivery_target. paidSource (competitor-new-keywords and web-mentions only; off by default; needs spend permission) also buys the signal from DataForSEO on every sweep: for competitor-new-keywords, Labs ranked keywords each tracker competitor (up to 5) newly ranks for at the tracker's market, not only tracked keywords; for web-mentions, pages DataForSEO's content index first saw naming the brand, off the client's own domains. The sweep is hourly but a purchase is reused from the archive while fresh, so it buys at most once a week per competitor (once a day for mentions); it is capped by the client's monthly budget, and a failed or over-budget read falls back to the free signal. Quote it first with estimate_cost. Answers 'tell me when rankings drop'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAlertRuleInput"
              },
              "example": {
                "clientId": "client_123",
                "kind": "rank-drop",
                "threshold": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_alert_rule": {
      "post": {
        "operationId": "update_alert_rule",
        "summary": "Update an alert rule",
        "description": "Changes a rule's threshold, cooldown or delivery (channel, webhookUrl — null removes it — emailRecipients, telegramChatId), or pauses and resumes it, or turns its paidSource on or off. Answers 'this alert is too noisy', 'send this to email instead' or 'mute this for now'. Pausing keeps the rule's history. paidSource (competitor-new-keywords and web-mentions only; off by default; needs spend permission) also buys the signal from DataForSEO on every sweep: for competitor-new-keywords, Labs ranked keywords each tracker competitor (up to 5) newly ranks for at the tracker's market, not only tracked keywords; for web-mentions, pages DataForSEO's content index first saw naming the brand, off the client's own domains. The sweep is hourly but a purchase is reused from the archive while fresh, so it buys at most once a week per competitor (once a day for mentions); it is capped by the client's monthly budget, and a failed or over-budget read falls back to the free signal. Quote it first with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAlertRuleInput"
              },
              "example": {
                "clientId": "client_123",
                "ruleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_alert_rule": {
      "post": {
        "operationId": "delete_alert_rule",
        "summary": "Delete an alert rule",
        "description": "Deletes a rule and every alert it ever fired. Answers 'remove this alert for good'. To stop it but keep its history, pause it with update_alert_rule instead. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteAlertRuleInput"
              },
              "example": {
                "clientId": "client_123",
                "ruleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/test_alert_rule": {
      "post": {
        "operationId": "test_alert_rule",
        "summary": "Send a test alert",
        "description": "Sends one test alert down a rule's channel now — Slack, Discord, webhook, email or Telegram — and says whether it was delivered, with the reason when it was not. Answers 'did the Discord alert work'. Nothing is recorded as fired and the cooldown is untouched. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestAlertRuleInput"
              },
              "example": {
                "clientId": "client_123",
                "ruleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_vendor_connections": {
      "post": {
        "operationId": "get_vendor_connections",
        "summary": "Which vendor accounts are connected",
        "description": "Which data vendors and AI assistants the agency has connected its own account for, and whether each last checked out. Answers 'why is this data missing' when a vendor was never connected. DataForSEO also gives balanceMicros, the account's balance now, and usable: false when it is 0 or below (it can go negative), when paid calls will fail with vendor_balance_empty even though connected is true. Never returns any part of a credential.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetVendorConnectionsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_client_integrations": {
      "post": {
        "operationId": "get_client_integrations",
        "summary": "Which consoles are connected for a client",
        "description": "Whether a client's Google Search Console and Google Analytics properties are connected and syncing, with the last sync error, and whether IndexNow is set up. backfill gives Search Console's sixteen-month history: the range asked for (from, to), how far it has got (collectedThrough, progress), its status — pending, running, retrying or complete — the rows stored and the days they span (rowsStored, storedFrom, storedThrough), and a note saying where Google's data for the property begins when it holds less than sixteen months. Answers 'is Search Console connected for this client' and 'is the history in yet'. Never returns tokens.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetClientIntegrationsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_costs": {
      "post": {
        "operationId": "get_costs",
        "summary": "Vendor spend by client",
        "description": "What the agency spent on data vendors per client over recent days, with request counts. Answers 'which clients cost us the most'. Amounts are US dollars.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "cost:view",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCostsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_client_costs": {
      "post": {
        "operationId": "get_client_costs",
        "summary": "Vendor spend for one client",
        "description": "What one client's data cost over recent days, by operation and by who caused it: surface (rest, mcp-http, web for the app's screens, assistant, or system for scheduled work such as the Sunday domain sweep) and actor (the user or API key, or the workflow), with request counts and the first and last time. Rows from before this was recorded have surface and actor null. Answers 'what are we paying for on this account' and 'who spent this'. The budget, what is left of it and a month-end forecast are get_budget_status. Amounts are US dollars.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "cost:view",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetClientCostsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_api_keys": {
      "post": {
        "operationId": "list_api_keys",
        "summary": "List API keys",
        "description": "The agency's live API keys with name, role, which client each is pinned to and when it was last used. Lists keys to audit or revoke. Never returns a key.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListApiKeysInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_api_key": {
      "post": {
        "operationId": "create_api_key",
        "summary": "Create an API key",
        "description": "Mints an API key, agency-wide or pinned to one client, with a role: client_viewer (read-only), analyst, manager, site_admin or admin. Answers 'give this integration its own key'. For an agent that runs one site, pin it to that client with site_admin: full control of that client — connecting consoles, crawls, onboarding — and none of the agency's settings, team, keys or billing; the key cannot even see other clients. A client-pinned key is at most site_admin, and site_admin needs a clientId. expiresInDays makes it stop working on its own; maxCostUsdPerCall caps what any one call with it may spend. The key is in the response once and can never be shown again. A key cannot be given more access than the caller has.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyInput"
              },
              "example": {
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_api_key": {
      "post": {
        "operationId": "revoke_api_key",
        "summary": "Revoke an API key",
        "description": "Stops a key working, immediately and for good. Answers 'this key leaked'. Safe to repeat; revoking the key making the call is allowed and takes effect on its next request.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeApiKeyInput"
              },
              "example": {
                "keyId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_api_activity": {
      "post": {
        "operationId": "list_api_activity",
        "summary": "List API activity",
        "description": "Recent tool calls made with the agency's keys — which key, which tool, which client, how it ended and how long it took — newest first. Lists who did what through the API and MCP. Inputs are never recorded.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListApiActivityInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_team_members": {
      "post": {
        "operationId": "list_team_members",
        "summary": "List the team",
        "description": "Everyone with access to the agency: email, name, role, and the clients each is limited to (empty means agency-wide). Also lists the clients a new member could be limited to. Answers 'who can see this account'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListTeamMembersInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_team_member": {
      "post": {
        "operationId": "add_team_member",
        "summary": "Add someone to the team",
        "description": "Gives an existing Seolyticize account access to the agency with a role — admin, manager, analyst or client_viewer — optionally limited to some clients. Answers 'give Sam access as an analyst'. The person must already have signed up; this never creates an account for them. Refused for someone already on the team, and for a client outside the caller's own reach. Owners can only be added by an owner, in the app.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddTeamMemberInput"
              },
              "example": {
                "email": "name@example.com",
                "role": "admin"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_team_member": {
      "post": {
        "operationId": "remove_team_member",
        "summary": "Remove someone from the team",
        "description": "Ends a member's access to the agency, by the membershipId list_team_members gives. Answers 'Sam has left'. Their account itself is untouched. The last owner cannot be removed. Safe to repeat.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveTeamMemberInput"
              },
              "example": {
                "membershipId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_vendor_credential": {
      "post": {
        "operationId": "save_vendor_credential",
        "summary": "Connect a vendor account",
        "description": "Stores the agency's own account for a data vendor or AI assistant — DataForSEO (the API login and API password, or leave login out and pass the Base64 login:password DataForSEO's panel shows as secret; the check also confirms the account is verified), SerpApi, a proxy pool (serpproxy: one URL per line), Google Ads (six values in googleAds), an Anthropic, OpenAI, Gemini or Perplexity key, and the rest get_vendor_connections names — and checks it works straight away with one free call. Answers 'connect our DataForSEO account'. A failed check gives errorCode (vendor_credentials_rejected, vendor_account_unverified, vendor_balance_empty, vendor_product_not_enabled) and next, the step that fixes it. Replaces any key already saved for that vendor. The response says whether the check passed; it never contains the key.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveVendorCredentialInput"
              },
              "example": {
                "provider": "dataforseo",
                "secret": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_vendor_credential": {
      "post": {
        "operationId": "remove_vendor_credential",
        "summary": "Disconnect a vendor account",
        "description": "Deletes the agency's saved account for one vendor. Answers 'stop using our DataForSEO account'. Anything that relied on it — keyword data from DataForSEO, an assistant's answers — stops until another is saved. Safe to repeat.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveVendorCredentialInput"
              },
              "example": {
                "provider": "dataforseo"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_branding": {
      "post": {
        "operationId": "get_branding",
        "summary": "Read the agency's branding",
        "description": "The agency's name, logo address and primary colour: what clients see on reports and portal links. Answers 'what will this report look like to the client'. Empty strings where nothing is set.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBrandingInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_branding": {
      "post": {
        "operationId": "set_branding",
        "summary": "Set the agency's branding",
        "description": "Renames the agency and sets the logo and colour on its reports and portal links. Answers 'put our logo on the reports'. The logo must be an https:// address and the colour six-digit hex such as #1f5ad6; empty strings clear them. Send all three: this replaces what is there.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetBrandingInput"
              },
              "example": {
                "name": "example",
                "logoUrl": "example",
                "primaryColor": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_connected_apps": {
      "post": {
        "operationId": "list_connected_apps",
        "summary": "List connected apps",
        "description": "Assistants and agent apps connected to the agency by signing in (MCP OAuth) rather than with an API key: which app, the role and client it was given, who approved it, and when it was last used. Answers 'what has access to our account'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListConnectedAppsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/disconnect_app": {
      "post": {
        "operationId": "disconnect_app",
        "summary": "Disconnect an app",
        "description": "Stops a signed-in app working, at once: its access and refresh tokens both end. Answers 'remove that assistant's access'. Takes the grantId from list_connected_apps. The app can only come back if somebody signs in and approves it again. Safe to repeat.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DisconnectAppInput"
              },
              "example": {
                "grantId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_billing": {
      "post": {
        "operationId": "get_billing",
        "summary": "Read the agency's plan",
        "description": "The agency's plan, its limits, how many clients it uses, and the subscription's status and renewal date. Answers 'how many more clients can we add'. `configured` is false where this deployment sells nothing — every agency is on the trial plan then, and that is not an error.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBillingInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_billing_link": {
      "post": {
        "operationId": "get_billing_link",
        "summary": "Get a link to pay or manage the plan",
        "description": "A Stripe address for a person to open: checkout for a plan (studio, agency or network), or — with no plan, for an agency already paying — the portal where cards, invoices and cancellation live. Answers 'upgrade our plan'. An agent cannot pay; hand the address to a person. Refused where this deployment has no billing set up.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBillingLinkInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_local_locations": {
      "post": {
        "operationId": "list_local_locations",
        "summary": "List a client's business locations",
        "description": "The client's business locations for local SEO: id, name, latitude and longitude. Answers 'which locations do we track in the map pack'. Pass an id to get_local_visibility, run_local_grid_scan or sync_local_reviews. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListLocalLocationsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_local_location": {
      "post": {
        "operationId": "add_local_location",
        "summary": "Add a business location",
        "description": "Adds a business location to a client for local SEO, at a latitude and longitude — the centre of every grid scan around it. Give its Google placeId (or cid) when known — get_business_profile finds both, with the coordinates — so scans match the listing itself, not any business with the same name. Answers 'start tracking this branch in the map pack'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddLocalLocationInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example",
                "lat": -90,
                "lng": -180
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_local_visibility": {
      "post": {
        "operationId": "get_local_visibility",
        "summary": "Map-pack visibility and reviews for a location",
        "description": "The latest grid scan for a search term at one location — the map-pack position at every point, and the share of points ranking in the top 3 and top 10, a summary (share of local voice with its band — dominant 80+, strong 60+, moderate 40+, weak 20+, critical — visibility points 3 for the top three and 1 for fourth to tenth, each compass quadrant and the worst, and the grid as rows north to south for a heatmap, with a text version), and a competitor table: every business the grid saw, with its share of local voice (the share of points where it holds a top-3 slot), points seen, average position, rating and reviews — plus an analysis of the location's reviews (rating, volume, recency, response rate). Answers 'where in town do we show up for this search'. scanned is false when that term has never been scanned there: no grid, rather than a grid of blanks that would read as invisible everywhere. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLocalVisibilityInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example",
                "term": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/run_local_grid_scan": {
      "post": {
        "operationId": "run_local_grid_scan",
        "summary": "Run a map-pack grid scan",
        "description": "Searches the term at every point of a size × size grid around the location (spacingKm apart, 1.5 by default — 0.5 for a dense city centre, 5 for a rural area) and records where the business appears in the map pack. Sizes 3, 5, 7, 9 (suburban or a wide service area) and 13 (rural or a large metro); device mobile asks as a phone, which sees a different pack; moreTerms (up to two) scans other terms on the same grid — the service, the brand with the town, a long-tail query — each its own scan. Every point of every term is a paid lookup, so a 7 × 7 grid is 49 lookups and 13 × 13 is 169: quote it with estimate_cost and get the user's go-ahead first. Runs in the background; read the result with get_local_visibility a few minutes later. With maxCostMicros, the scan is refused before it starts when its estimate is over the limit. Answers 'scan our map-pack visibility now'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunLocalGridScanInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example",
                "term": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/sync_local_reviews": {
      "post": {
        "operationId": "sync_local_reviews",
        "summary": "Collect a location's Google reviews",
        "description": "Collects the location's latest Google reviews (up to 50) from the vendor. Paid: quote it with estimate_cost first. Runs in the background and takes a few minutes; read the analysis with get_local_visibility afterwards. A second request within the hour lands on the collection already running rather than paying twice. With maxCostMicros, it is refused before it starts when its estimate is over the limit. Answers 'pull in our latest reviews'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncLocalReviewsInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_local_seo_audit": {
      "post": {
        "operationId": "get_local_seo_audit",
        "summary": "Local SEO audit of a location",
        "description": "Scores one location's local SEO 0–100 (a heuristic, said so in the answer) from six weighted parts, each check full, partial or low with the reason, or null when not measured — then left out and the other weights rescaled: the Google Business Profile (25: primary category against the homepage, about four secondary categories, posts, photos, Q&A, hours), reviews (20: at least 10, the rating, the last three months, six months' monthly flow and gaps over three weeks, owner response rate, and a fake-review flag when two of six patterns match), the site (20: city and service in the title and H1, visible NAP, a tel: link, a map embed, location pages over 60% unique by the city-swap test, gates at 30 and 50 location pages), NAP and citations (15, the check_nap_consistency comparison; directories: true adds the directory citations), LocalBusiness schema (10: a subtype, geo to five decimals, priceRange under 100 characters, a unique @id per location with branchOf) and links (10); plus a rating spread that leans to five stars, review gating, service pages, location pages within three clicks, hours on the site, trust badges, the PostalAddress parts, the subtype that fits the vertical, areaServed, retired VehicleListing and SpecialAnnouncement markup and, with duplicates, other listings at the same address or phone. gbpChecklist scores the 25-field profile checklist (2/1/0 per field, null where DataForSEO returns nothing — verified status, Q&A, videos, products, photo dates — weighted by vertical, banded 90/75/50/25); grid reads back the latest grid scan for the main service (share of local voice, visibility points, the worst quadrant, a heatmap); mapsHealth combines profile 25, grid 20, reviews 20, NAP 15, schema 10 and rival standing 10. Detects storefront, service-area business (which skips the map and address checks) or hybrid, and the vertical; adds listing completeness 0–100 and, with competitorRadiusKm, the competitors per km² in the primary category. Reviews come from sync_local_reviews; posts from a get_business_posts task passed as postsTaskId. Answers 'how good is our local SEO' and 'what should we fix first for the map pack'. useListing reads the live listing and its Q&A, and competitorRadiusKm one business search, all paid: quote with estimate_cost. Free with useListing false and competitorRadiusKm 0.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLocalSeoAuditInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_backlink_audit": {
      "post": {
        "operationId": "get_backlink_audit",
        "summary": "Audit a client's backlinks",
        "description": "The client's backlinks, each scored from signals an agency can check — source authority, how many sites the source links out to, and the anchor — with a verdict of healthy, review or toxic and the reasons. Also the top referring domains, the top anchors, and the links our own crawler found (page-level, ours alone). Brand terms come from the client's name and domain, so a branded anchor is not read as paid; pass moneyTerms (commercial phrases such as 'cheap flights') to flag exact-match anchors. Answers 'are any of our links a problem'. 'review' means look at it, not that it is bad. domain is null when the client has no site yet. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBacklinkAuditInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_backlink_health": {
      "post": {
        "operationId": "get_backlink_health",
        "summary": "How healthy is the link profile",
        "description": "Scores the client's link profile 0–100 (a heuristic, said so) from seven factors, each good, warn or critical with its figures and the source they came from (the vendor's synced index, our own link index, the domain graph): referring domains (20: over 100 good, under 20 critical), quality distribution (20: the linking sites' authority, and domain diversity — one site over 10% of the links warns, over 25% is critical), anchor naturalness (15: the anchor bands of get_anchor_distribution), toxic ratio (20: the share of linking sites get_toxic_link_risk calls toxic), velocity (10: a fall in referring domains of over 20% a quarter is critical), follow ratio (5: over 60% followed good, under 40% critical) and geographic relevance (10: the linking sites' TLD and country mix against the client's market; 80% or more from other countries flags a private network). Each factor carries its source's confidence (DataForSEO 1.0, our link index 0.7, Common Crawl 0.5), which scales its weight; a number only when at least four factors have data, and never from presence-only sources alone (NOT ASSESSED); otherwise INSUFFICIENT DATA (X/7). industry (saas, ecommerce, local, publisher, agency) judges the anchors against that industry's natural ranges. Also the profile's toxic signals: 50+ directory links, linking pages with 10,000+ outbound links, more than 50 links from one site, linking pages under 100 words, reciprocal links. Pass moneyTerms to tell exact and partial-match anchors apart. Spam scores sharpen the toxic ratio: fetchSpamScores: true buys them inside this call (one paid DataForSEO request of up to 1,000 linking sites, the price of get_backlink_spam_scores; sites scored in the last 30 days are reused free; quote it with estimate_cost or dryRun first), or pass spamScores you already have. Answers 'how healthy are our backlinks' and 'is our link profile at risk'. Free without fetchSpamScores.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBacklinkHealthInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_link_checks": {
      "post": {
        "operationId": "get_link_checks",
        "summary": "Do the linking pages still link?",
        "description": "What our own crawler last saw on each page said to link to the client: live (the link is there), lost (the page no longer links), unknown (the page could not be read), moved (the page redirected elsewhere and the link is not at the new address, with movedTo) or unverifiable_js (the page is a JavaScript app shell, so its links cannot be seen without a browser), with counts, and rendered: true where the last check read the page in a browser. Only lost is a removal. Read from the last check, never fetched now. Answers 'which links have we lost'. Run recheck_links to check again, or recheck_links with render: true to read the unverifiable_js pages in a browser. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLinkChecksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/recheck_links": {
      "post": {
        "operationId": "recheck_links",
        "summary": "Re-check the pages that link to a client",
        "description": "Sends our crawler to the pages said to link to the client to see whether each still does — slowly and politely, so it takes a while; read the result with get_link_checks. A second request within the hour lands on the check already running. render: true instead reads, in a real browser, the pages the last check marked unverifiable_js (app shells whose links JavaScript draws) — or the sourceUrls given, if the link checks know them — up to 25 a run, and re-judges each link as live, lost or moved (a page that draws nothing even in the browser stays unverifiable_js, and one that will not load keeps its verdict); it runs in the background, so poll get_run_status with job 'links' and the runId, then read get_link_checks (rendered: true on those pages). No vendor charge, but it visits other people's sites on the client's behalf, so it needs client:manage. Refused when the client has no rank tracker yet (HTML) or no page is waiting on a browser (render: nothing_to_render). Answers 'check our links again' and 'check the JavaScript pages properly'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecheckLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_backlink_spam_scores": {
      "post": {
        "operationId": "get_backlink_spam_scores",
        "summary": "The vendor's spam scores for linking sites",
        "description": "The data vendor's own spam score (0–100, null when it has none) for each domain you pass — usually the sources from get_backlink_audit. A second opinion beside ours: a link both call bad is one to act on. Paid, one purchase per call however many domains (up to 1000): quote it with estimate_cost and get the user's go-ahead first. Answers 'what does the vendor think of these links'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBacklinkSpamScoresInput"
              },
              "example": {
                "clientId": "client_123",
                "domains": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_link_prospects": {
      "post": {
        "operationId": "list_link_prospects",
        "summary": "List a client's link prospects",
        "description": "The client's outreach list: sites worth asking for a link, each with its stage (identified, contacted, replied, won, rejected), why it was added, when it last moved, the contact to write to and, for won links, whether the last link check found the link live on its page — most recently moved first. Answers 'where is our link outreach' and 'are the links we won still up'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListLinkProspectsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_link_prospects": {
      "post": {
        "operationId": "add_link_prospects",
        "summary": "Add sites to a client's outreach list",
        "description": "Adds linking-site prospects to the client's outreach list at the identified stage — typically the domains get_link_intersect finds linking to competitors but not the client, with that as the reason. Give targetUrl when the prospect is one page — a dead page to reclaim, a thread to answer, an article that mentions the brand — so each page is its own row; without it the prospect is the whole site. A site or page already on the list is left at its current stage, never reset. Answers 'add these sites to our outreach'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddLinkProspectsInput"
              },
              "example": {
                "clientId": "client_123",
                "prospects": [
                  {
                    "sourceDomain": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_link_prospect_status": {
      "post": {
        "operationId": "set_link_prospect_status",
        "summary": "Move a link prospect to another stage",
        "description": "Moves one prospect on the client's outreach list to identified, contacted, replied, won or rejected, and saves its contact email. For won, give linkUrl — the page the link sits on (a page prospect defaults to its own page): a link check is queued to confirm the link is live, and the weekly link check keeps verifying it (list_link_prospects shows the result). Take the id from list_link_prospects. Answers 'we heard back from this site' and 'we got the link'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetLinkProspectStatusInput"
              },
              "example": {
                "clientId": "client_123",
                "prospectId": "example",
                "status": "identified"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/analyse_server_log": {
      "post": {
        "operationId": "analyse_server_log",
        "summary": "Analyse a server access log",
        "description": "Reads a web server access log in combined format (nginx's and Apache's default) passed as text, and reports what search and AI crawlers spent their visits on: analysis.byBot (hits per crawler), topPaths, errorPaths (path, status, hits), wastedOnErrors and wastedOnRedirects (shares of crawler requests that returned no content), aiCrawlerShare, aiByPurpose (AI agents' requests split into training crawls — GPTBot, ClaudeBot, CCBot, Meta, Bytespider, Amazonbot — search indexing — OAI-SearchBot, Claude-SearchBot, PerplexityBot, Applebot, DuckAssistBot — and user fetches — ChatGPT-User, Claude-User, Perplexity-User, MistralAI-User, an assistant reading the page because someone asked it something), aiUserPaths (the pages assistants fetched for people: the nearest a log gets to citations), totalHits and totalBytes. Also linesRead, linesUnparsed (lines in a format it did not recognise — many means the wrong format, not a quiet site), humanHits and truncated. Up to 64 MB per call; split a bigger log and call once per part. Nothing is stored. Answers 'what is Googlebot actually crawling on our site' and 'which of our pages are AI assistants reading'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnalyseServerLogInput"
              },
              "example": {
                "clientId": "client_123",
                "contents": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_report_schedules": {
      "post": {
        "operationId": "list_report_schedules",
        "summary": "List report schedules",
        "description": "Every schedule that emails one of a client's saved reports: which report, monthly or weekly, the recipients, whether it is paused and when it last sent. Lists who receives what and how often. send_report sends to these recipients, so a report with no schedule has nobody to send to.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListReportSchedulesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/schedule_report": {
      "post": {
        "operationId": "schedule_report",
        "summary": "Schedule a report",
        "description": "Puts one of a client's saved reports (see list_reports, create_report) on a monthly or weekly cadence for a list of recipients. Answers 'send this report to the client every month'. The scheduled send runs on its own; send_report sends one now, to every recipient of every schedule for that report. A report can have more than one schedule.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleReportInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example",
                "recipients": [
                  "name@example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_report_schedule": {
      "post": {
        "operationId": "update_report_schedule",
        "summary": "Change a report schedule",
        "description": "Changes a schedule's cadence or recipients, or pauses or resumes it. Answers 'add the new marketing lead to the monthly report' and 'stop the weekly email while the client is away'. Recipients, when given, replace the whole list. A paused schedule sends nothing until resumed.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReportScheduleInput"
              },
              "example": {
                "clientId": "client_123",
                "scheduleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_report_schedule": {
      "post": {
        "operationId": "delete_report_schedule",
        "summary": "Delete a report schedule",
        "description": "Removes a schedule for good: its recipients stop receiving that report. Answers 'stop sending this report'. The report itself and its past sends are kept. To stop it for a while instead, pause it with update_report_schedule.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteReportScheduleInput"
              },
              "example": {
                "clientId": "client_123",
                "scheduleId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/archive_report": {
      "post": {
        "operationId": "archive_report",
        "summary": "Retire a saved report",
        "description": "Retires a client's saved report so it is no longer sent, by schedule or by hand. Answers 'we no longer send this report'. Archived rather than deleted: reports already sent to the client stay downloadable. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArchiveReportInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_competitors": {
      "post": {
        "operationId": "add_competitors",
        "summary": "Add competitors to a tracker",
        "description": "Adds competitor domains to a rank tracker, so share of voice and the competitor comparisons measure them on the same keywords. Answers 'compare us with these sites'. Returns the tracker's full competitor list. Domains already there are left as they are.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddCompetitorsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "domains": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_competitors": {
      "post": {
        "operationId": "remove_competitors",
        "summary": "Remove competitors from a tracker",
        "description": "Stops measuring the named competitor domains on a rank tracker. Answers 'we no longer compete with this site'. Returns the tracker's remaining competitors. Naming a domain that is not on the list is not an error.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveCompetitorsInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "domains": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_connection_link": {
      "post": {
        "operationId": "get_connection_link",
        "summary": "Get a link for a person to connect a service",
        "description": "The link a PERSON must open to connect one of a client's accounts — Google Search Console (search_console), Search Console sitemap management (search_console_sitemaps), Google Analytics 4 (google_analytics), Yandex Webmaster (yandex_webmaster) or a Google Business Profile listing (google_business_profile) — with what they will be asked to approve and what is connected now. Answers 'connect Search Console for this client' and 'did the connection work'. An agent cannot complete these itself: the account owner signs in to that service and grants access. Give the url and the steps to your human, then call this again to check state. The person must be signed in to Seolyticize with permission to manage the client. google_analytics needs ga4PropertyId (the numeric property id, not a G- measurement id); google_business_profile needs locationId; search_console takes an optional propertyUrl (default: the client's site, https://domain/; a Domain property is sc-domain:example.com). Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetConnectionLinkInput"
              },
              "example": {
                "clientId": "client_123",
                "service": "search_console"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_google_service_account": {
      "post": {
        "operationId": "get_google_service_account",
        "summary": "Get the agency's Google service account",
        "description": "The email address of the agency's own Google service account, made the first time it is asked for. Answers 'what do I add in Search Console so we can connect without signing in'. A client's property owner adds this address as a user — Search Console: Settings → Users and permissions, Restricted; GA4: Admin → Property access management, Viewer — and then connect_search_console_service_account or connect_google_analytics_service_account connects it with no Google sign-in. The address is the agency's alone; give it to your human to pass on. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGoogleServiceAccountInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_search_console_service_account": {
      "post": {
        "operationId": "connect_search_console_service_account",
        "summary": "Connect Search Console by service account",
        "description": "Connects a client's Search Console property as the agency's Google service account (get_google_service_account), once the property's owner has added that address as a user. Answers 'they added our address, connect Search Console'. Access is checked with Google first: with no propertyUrl, the client's site is tried as a Domain property (sc-domain:) and then as https:// and https://www. URL-prefix properties, and the first the account can read is connected. If none can be read yet, it is refused with the exact steps for the owner. Starts the sixteen-month backfill. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectSearchConsoleServiceAccountInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_google_analytics_service_account": {
      "post": {
        "operationId": "connect_google_analytics_service_account",
        "summary": "Connect GA4 by service account",
        "description": "Connects a client's GA4 property as the agency's Google service account, once the property's owner has added that address with the Viewer role. Answers 'they added our address in GA4, connect it'. propertyId is GA4's numeric property id (Admin → Property details), not a G- measurement id. Access is checked with Google first, and refused with the exact steps when it is not granted yet. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectGoogleAnalyticsServiceAccountInput"
              },
              "example": {
                "clientId": "client_123",
                "propertyId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_yandex_with_token": {
      "post": {
        "operationId": "connect_yandex_with_token",
        "summary": "Connect Yandex Webmaster with a token",
        "description": "Connects a client's Yandex Webmaster with an OAuth token a person made in their own Yandex app (get_connection_link with yandex_webmaster returns the steps), instead of signing in through Seolyticize. Answers 'here is the Yandex token, connect it'. Yandex is asked whose token it is and the client's site is matched against that account's verified hosts; the response says which host matched, or that none did. Works even where this deployment has no Yandex sign-in set up. The token is stored sealed and never returned. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectYandexWithTokenInput"
              },
              "example": {
                "clientId": "client_123",
                "token": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_portal_links": {
      "post": {
        "operationId": "list_portal_links",
        "summary": "List client portal links",
        "description": "The live white-label portal links for a client: label, when each was made, and when it was last opened. Lists who can currently see the client's results without an account. The addresses themselves are not shown — they exist only at the moment a link is made.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListPortalLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_portal_link": {
      "post": {
        "operationId": "create_portal_link",
        "summary": "Create a client portal link",
        "description": "Makes a white-label link that shows one client their own dashboard under the agency's name, with no sign-in. Answers 'give the client a link to their results'. The full address is in this response once and can never be shown again; send it to the client and keep it out of logs. Anyone holding it can see that client's results until it is revoked.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePortalLinkInput"
              },
              "example": {
                "clientId": "client_123",
                "label": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_portal_link": {
      "post": {
        "operationId": "revoke_portal_link",
        "summary": "Revoke a client portal link",
        "description": "Stops a portal link working, immediately and for good. Answers 'that link was forwarded' or 'the engagement ended'. A link that is already revoked, or is not this client's, is refused rather than reported as done.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokePortalLinkInput"
              },
              "example": {
                "clientId": "client_123",
                "linkId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/onboard_site": {
      "post": {
        "operationId": "onboard_site",
        "summary": "Onboard a site in one call",
        "description": "Answers 'set this site up'. Makes the client, project, site and rank tracker — or finds the client already here for this domain, so calling it twice is safe — issues the IndexNow key and a Google site verification for the agency's own Google account, sets up cookieless analytics, and returns one deploy manifest: files to serve at exact paths, tags for the <head>, the analytics snippet placed for the framework given, and CSP entries, plus scheduledPaidWork: anything paid it leaves running on a schedule (nothing, for a new client: its tracker runs only once it has keywords, weekly unless trackerFrequency says otherwise, and the weekly domain sweep stays off until set_domain_sweep). Deploy all of it, then call verify_site. No Google sign-in or Search Console settings are needed at any point. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OnboardSiteInput"
              },
              "example": {
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/apply_manifest": {
      "post": {
        "operationId": "apply_manifest",
        "summary": "Bring a client to what its repo declares",
        "description": "Answers 'provision our product from its manifest' in one call that is safe to run on every deploy. Takes what a repository declares about its site (domain, framework, verification, tracker cadence, budget and its alert share, domain sweep, deploy hook, analytics paths and partners, crawl settings, default alerts and where they go, brief and brand terms, facts, goals, funnels) and brings the client to it through the existing tools, each with its own permission and checks. Each part is compared with what is there first: a step is kept when it would write nothing, ran when it changed something, would_run on a dry run. Fields the manifest leaves out are left as they are. files (the IndexNow key and Google verification file, which are public) come back on every real run. env lists each environment variable to set: build (read at build time), runtime and secrets, with public ids as values and secrets only as a placeholder naming the tool that issues them. A new deploy hook's secret is in its step's result only, once. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplyManifestInput"
              },
              "example": {
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/move_site": {
      "post": {
        "operationId": "move_site",
        "summary": "Move a client to a new domain",
        "description": "Answers 'the site moved to a new domain'. Keeps the client, its history and its analytics site key, and moves everything that follows the domain: the site, its rank trackers (frequency unchanged), its own brand in AI visibility, the IndexNow key, the analytics hostnames (the old ones are still accepted for overlapDays, then refused), and the deploy hook (same URL; sitemaps on the old domain follow, others are listed in otherHosts; its next call records a fresh baseline). Never changes the budget or the domain sweep. notMoved names what cannot follow, with the next step. Safe to repeat: a second call answers alreadyMoved: true with the same manifest and changes nothing. Issues a Google verification for the new domain and returns the deploy manifest to put on it (IndexNow key file, verification file, tag or TXT record), and adds a 'Domain moved' note to the timeline. Then deploy the manifest on the new domain and call verify_site, which verifies it and adds the new Search Console property. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveSiteInput"
              },
              "example": {
                "clientId": "client_123",
                "newDomain": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/verify_site": {
      "post": {
        "operationId": "verify_site",
        "summary": "Verify a deployed site and finish onboarding",
        "description": "Answers 'I deployed it, is everything connected'. After the onboard_site manifest is live, checks and completes everything in one call: the IndexNow key file, Google ownership (and then adds and connects the Search Console property, with its sixteen months of history), whether analytics has received its first event, that robots.txt and the sitemap answer, and starts the first crawl. Returns a checklist where every item not done carries the exact fix and the next call. Safe to call again. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifySiteInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_next_steps": {
      "post": {
        "operationId": "get_next_steps",
        "summary": "What to do next for a site",
        "description": "The doctor call. Answers 'what is left to do for this site, and what call does it' and 'what is not connected for this client, and what does each missing piece block'. missing lists the ids of every item not done. The onboarding checklist with live status — done, todo, in progress, failed or blocked and why — each with the exact tool and arguments to call next; then the optional connections that unlock more tools (Bing Webmaster key, PageSpeed / Chrome UX Report key, alert delivery, rank tracker keywords, AI visibility schedule, analytics goals, crawl schedule), each with its status and call; then, once the site is set up, the weekly loop's calls with their arguments. Reads only; changes nothing. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetNextStepsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/bootstrap_keywords": {
      "post": {
        "operationId": "bootstrap_keywords",
        "summary": "Free keyword ideas for a new site",
        "description": "Keyword ideas that cost nothing, for a site too new for Search Console rows and an agency with no vendor credit: Google autocomplete suggestions and questions around each seed (default: the site's name), and the page names in competitors' sitemaps (competitorDomains). Each idea has its source and what it came from; there are no volumes, because none of these sources publishes one — add the best to a rank tracker, or price them later with get_keyword_metrics. Answers 'what should a brand-new site target'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BootstrapKeywordsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/issue_site_verification": {
      "post": {
        "operationId": "issue_site_verification",
        "summary": "Issue a Google site verification",
        "description": "Answers 'prove we own the site to Google without anyone opening Search Console'. Asks Google for a verification token for the agency's own Google account and returns what to deploy: a file at the site root (file), a <head> tag (meta) or a TXT record (dns). Then call verify_site_ownership. onboard_site does this for you. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueSiteVerificationInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/verify_site_ownership": {
      "post": {
        "operationId": "verify_site_ownership",
        "summary": "Verify site ownership and connect Search Console",
        "description": "Answers 'the verification file is live, connect Search Console'. Has Google check the deployed file, tag or record (with no method, each is tried), which makes the agency's Google account a verified owner; then adds the property to its Search Console and connects it to the client, history included. addOwners makes other Google accounts owners too, so the site's people keep their own access. verify_site does this for you. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifySiteOwnershipInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_invite_code": {
      "post": {
        "operationId": "create_invite_code",
        "summary": "Create an invite code for a site's agent",
        "description": "Answers 'let an agent connect its own site without our admin key'. Makes a code to hand to the agent that runs one site. The agent sends it, with its domain, to POST /api/v1/claim (no key needed) and gets back a key pinned to the one new client for that site, with the site_admin role: full control of that client, nothing else in the agency. The code is in this response once. maxUses (default 1) is how many sites it can claim; expiresInDays ends the code, keyExpiresInDays the keys it makes, and keyMaxCostUsdPerCall caps what any one call with those keys may spend. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInviteCodeInput"
              },
              "example": {
                "label": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_invite_codes": {
      "post": {
        "operationId": "list_invite_codes",
        "summary": "List invite codes",
        "description": "Lists the agency's invite codes — label, uses left, expiry, whether revoked — never the codes themselves. Answers 'which invite codes are out there'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListInviteCodesInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_invite_code": {
      "post": {
        "operationId": "revoke_invite_code",
        "summary": "Revoke an invite code",
        "description": "Stops an invite code being claimed again. Answers 'that code was shared too widely'. Keys already made from it keep working until revoked with revoke_api_key. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeInviteCodeInput"
              },
              "example": {
                "inviteCodeId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_deploy_hook": {
      "post": {
        "operationId": "create_deploy_hook",
        "summary": "Create a deploy hook",
        "description": "Answers 'tell search engines whenever we deploy'. Makes the client's deploy hook, which the site's pipeline calls after every deploy. Each call reads the sitemap, compares it with the last one, and submits the new and changed pages to IndexNow; the first call records the baseline only. A Forumulate webhook subscribed to page.live can point at it too: each published page is submitted when it goes live and noted on the timeline as a publish. Returns hookId and url (neither is secret), secret (sent as Authorization: Bearer; shown only here), webhookUrl (the secret in the path, only for senders that cannot set a header, such as Netlify, Vercel, Cloudflare Pages and Forumulate; treat that whole URL as a secret, since tools print URLs; it works for as long as the hook does, by design, and pathUrl: false leaves it out of the answer) and howToCall for each platform. A client that already has a hook is refused with hook_exists and nothing changes; rotate_deploy_hook replaces the secret. With ifMissing: true an existing hook is left alone and returned as {created: false} without a secret, so a provisioning script can run it on every deploy safely. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeployHookInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/rotate_deploy_hook": {
      "post": {
        "operationId": "rotate_deploy_hook",
        "summary": "Rotate the deploy hook's secret",
        "description": "Answers 'that deploy hook secret leaked, replace it' and 'point the hook at another sitemap'. Replaces the secret: the old secret and the old webhookUrl stop working at once, while hookId, url and the sitemap baseline stay. Returns the new secret and webhookUrl once, with howToCall. Pass sitemapUrl to change the sitemap read; without it the current one is kept. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RotateDeployHookInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_deploy_hook": {
      "post": {
        "operationId": "get_deploy_hook",
        "summary": "Get the deploy hook's status",
        "description": "Answers 'did the last deploy notify search engines' and 'does this client have a deploy hook'. exists, then (when it does) the hook's createdAt, lastCalledAt (the last call, whatever came of it), lastRunAt (the last run that read a sitemap), lastResult (led by the call's source and ref in brackets when it sent them), how many sitemap pages it knows, and howToCall.coolify: the post-deploy command, which reads the URL and secret from SEOLYTICIZE_DEPLOY_HOOK_URL and SEOLYTICIZE_DEPLOY_HOOK_SECRET. hookId is not secret. Never the secret itself: a lost one is replaced with rotate_deploy_hook. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDeployHookInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_deploy_hook": {
      "post": {
        "operationId": "revoke_deploy_hook",
        "summary": "Revoke the deploy hook",
        "description": "Answers 'stop this deploy hook'. Deletes the client's deploy hook, so its URL and secret stop working at once. To replace a leaked secret and keep the hook, use rotate_deploy_hook. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeDeployHookInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/refresh_rankings": {
      "post": {
        "operationId": "refresh_rankings",
        "summary": "Capture rankings now",
        "description": "Captures the client's rank tracker now instead of at its next scheduled run: every tracked keyword on every device the tracker reads, each a paid lookup. Answers 'get me today's positions'. Quote it with estimate_cost first; with maxCostMicros the run is refused before it starts when its estimate is over the limit. Runs in the background: poll get_run_status with job 'rank' (or pass the jobId it returns to wait_for_job), then read get_rank_history or get_rank_summary. A second request within the same minute lands on the run already going rather than paying twice.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRankingsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/refresh_domain_data": {
      "post": {
        "operationId": "refresh_domain_data",
        "summary": "Refresh domain and backlink data now",
        "description": "Refreshes everything bought about the client's domain — overview, ranked keywords, competitors, top pages and the backlink profile — plus what up to five tracked competitors rank for and who links to them. Answers 'update the backlinks and keyword data'. The dearest thing the product does: quote it with estimate_cost first; with maxCostMicros the refresh is refused before it starts when its estimate is over the limit. Runs in the background for a few minutes: poll get_run_status with job 'domain' (or pass the jobId it returns to wait_for_job). A second request within the hour lands on the refresh already going.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshDomainDataInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_run_status": {
      "post": {
        "operationId": "get_run_status",
        "summary": "Get the status of a run",
        "description": "How a run started with refresh_rankings (job 'rank'), refresh_domain_data (job 'domain') or recheck_links (job 'links', including a browser re-check with render) is going: running, done or failed, and — when it failed or captured only some keywords — the reason, written for an agency to act on (a missing vendor key, an unreachable site). Answers 'did that capture work'. A run id that is not this client's, or that has aged out, reads as unknown.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRunStatusInput"
              },
              "example": {
                "clientId": "client_123",
                "job": "rank",
                "runId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_brand_mentions": {
      "post": {
        "operationId": "get_brand_mentions",
        "summary": "Find recent mentions of a brand or phrase",
        "description": "Who has written about a brand or phrase lately — the page, its title and snippet, when it was published, and how it read (positive, negative or neutral) — one result per publishing domain, up to 50. Answers 'who is talking about us' and finds unlinked mentions worth asking for a link. A paid lookup on the client's account: quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBrandMentionsInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_trends": {
      "post": {
        "operationId": "get_keyword_trends",
        "summary": "Get Google Trends interest for terms",
        "description": "Interest over time from Google Trends for up to five terms in the United States, each on a 0–100 scale relative to its own peak — so it shows when people care, not how many. Kept for existing callers; get_google_trends does the same for any market or worldwide, with regions, rising searches and news, YouTube, image or shopping search, and is the one to use. Answers 'is this seasonal' and 'is this growing'. Different from get_search_demand, which counts people in our own panel. A paid lookup on the client's account: quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordTrendsInput"
              },
              "example": {
                "clientId": "client_123",
                "terms": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/estimate_domain_traffic": {
      "post": {
        "operationId": "estimate_domain_traffic",
        "summary": "Estimate search traffic for domains",
        "description": "A vendor's current estimate of monthly organic search traffic and ranking keywords for up to 100 domains, bought now. get_batch_analysis gives the same traffic beside rank, backlinks and referring domains for up to 200. Answers 'how much search traffic do these competitors get'. Modelled from rankings, not measured visits. batch_domain_metrics reads what is already stored for free; use this when those figures are missing or stale. A paid lookup on the client's account: quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateDomainTrafficInput"
              },
              "example": {
                "clientId": "client_123",
                "targets": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_subdomain_traffic": {
      "post": {
        "operationId": "get_subdomain_traffic",
        "summary": "See which subdomains carry a site's search traffic",
        "description": "A site's subdomains ranked by estimated organic traffic and ranking keywords, up to 50. Answers 'which parts of this site carry its search presence'. get_domain_facts lists subdomain names from certificate logs for free but says nothing of their traffic. A paid lookup on the client's account: quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSubdomainTrafficInput"
              },
              "example": {
                "clientId": "client_123",
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_domain_technologies": {
      "post": {
        "operationId": "get_domain_technologies",
        "summary": "See what a domain is built with",
        "description": "The technologies our own crawler detected on any domain — CMS, analytics, commerce, CDN and so on — with the version most pages showed and how many pages showed it, as of the day it was last crawled. Answers 'what is this site built on'. Free. Null when our crawler has never fetched the domain, which says nothing about what it runs.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDomainTechnologiesInput"
              },
              "example": {
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/rename_keyword_list": {
      "post": {
        "operationId": "rename_keyword_list",
        "summary": "Rename a keyword list",
        "description": "Gives a keyword list a new name. Answers 'call that list something else'. Refused when another list for the same client (or the agency) already has the name.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenameKeywordListInput"
              },
              "example": {
                "listId": "example",
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_keyword_list": {
      "post": {
        "operationId": "delete_keyword_list",
        "summary": "Delete a keyword list",
        "description": "Deletes a keyword list and the keywords on it, for good. Answers 'get rid of that list'. Keywords a tracker took from the list stay tracked.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteKeywordListInput"
              },
              "example": {
                "listId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_list_to_tracker": {
      "post": {
        "operationId": "add_list_to_tracker",
        "summary": "Track a keyword list",
        "description": "Adds every keyword on a list to one of the client's rank trackers. Answers 'start tracking everything on that list'. Keywords for another country, language or engine than the tracker reads are skipped and listed with the reason, never tracked in the wrong market. Each added keyword is a paid lookup on every future run, so quote the tracker with estimate_cost afterwards if cost matters; refused when the plan's keyword allowance would be exceeded.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddListToTrackerInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example",
                "listId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/query_keyword_list": {
      "post": {
        "operationId": "query_keyword_list",
        "summary": "Filter and sort a keyword list",
        "description": "One list's keywords with the metrics last read for each — volume, keyword difficulty, CPC (micro-USD), competition, intent, SERP features and when they were read — plus tags and notes, filtered by text, tags (all must match), untagged, intent and volume or difficulty ranges, and sorted by term, volume, difficulty, cpc, added or refreshed. Keywords with no metrics sort last. format: csv also returns the page as CSV for a spreadsheet. Answers 'which keywords on that list are easy and over 1,000 searches' and 'export that list'. Metrics are null until refresh_keyword_list_metrics has run. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryKeywordListInput"
              },
              "example": {
                "listId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/tag_list_keywords": {
      "post": {
        "operationId": "tag_list_keywords",
        "summary": "Tag keywords on a list",
        "description": "Puts tags on keywords in a list, or takes them off with remove: true — by keywordId from query_keyword_list, or keywordIds: 'all' for every keyword on the list. Answers 'tag these as pillar' and 'take q3 off the whole list'. Tags are case-insensitive labels up to 40 characters; changed counts the keywords that gained or lost one. For a tracker's keywords use tag_keywords. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagListKeywordsInput"
              },
              "example": {
                "listId": "example",
                "keywordIds": [
                  "example"
                ],
                "tags": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/refresh_keyword_list_metrics": {
      "post": {
        "operationId": "refresh_keyword_list_metrics",
        "summary": "Refresh a keyword list's metrics",
        "description": "Re-reads volume, keyword difficulty, CPC, competition, intent and SERP features for every Google keyword on a list from DataForSEO Labs, in bulk (one read per market per 700 keywords), and stores them on the list. Answers 'update the numbers on that list'. onlyOlderThanDays skips keywords refreshed more recently, so a big list is not bought twice in a week. Keywords for other engines, or markets the research index does not cover, are skipped with the reason; terms the index has nothing for are listed in noData and their old figures cleared. clientId is the account billed: a client's list is refreshed under its own client, an agency list under any client the caller names. A paid lookup unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshKeywordListMetricsInput"
              },
              "example": {
                "clientId": "client_123",
                "listId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_changes": {
      "post": {
        "operationId": "get_search_changes",
        "summary": "What changed in search",
        "description": "Two periods of Google search compared, by query or by page: what is new (shown now, not at all before), what was lost, and the biggest gainers and losers by clicks. Answers 'which queries did we start ranking for', 'what did we lose this week' and 'which pages are growing'. brand narrows to branded or non-branded queries (non-branded is what SEO work moves); country and device segment it. Periods end on the newest day Google has finished counting. searchType reads image, video, news, Discover or Google News instead of web (Discover and Google News by page only). Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchChangesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_brand_split": {
      "post": {
        "operationId": "get_brand_split",
        "summary": "Branded vs non-branded search",
        "description": "Google search clicks and impressions split into branded (the query names the client) and non-branded, by day, week or month, with the property total and the anonymised remainder Google withholds queries for. Answers 'is non-branded traffic growing' — the number content and SEO work actually move. Brand terms come from the client brief (update_client_brief brandTerms), or the client's name and domain. searchType picks web (default), image, video or news; Discover and Google News have no queries to split. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBrandSplitInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_query_page_swaps": {
      "post": {
        "operationId": "get_query_page_swaps",
        "summary": "Queries answered by a different page",
        "description": "Queries where Google now sends searchers to a different page of the site than in the previous period, with both pages and their clicks. Answers 'is Google confused about which page to rank' — a swap is usually two pages competing (merge them or fix internal links) or a new page taking over. Every Search Console query, not only tracked keywords (get_url_swaps covers those). Each swap names the registry's owner for the query and whether Google's current page is it. searchType picks web (default), image, video or news. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetQueryPageSwapsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_content_groups": {
      "post": {
        "operationId": "get_content_groups",
        "summary": "Search traffic by section",
        "description": "Google search clicks, impressions and position rolled up by section of the site, two periods compared. Answers 'how is the blog doing against the guides' and 'which template is losing traffic'. groups are matched in order against each page's path, first match wins (* matches anything, so '/blog/*'); without groups, pages are grouped by their first path segment. searchType reads image, video, news, Discover or Google News instead of web. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetContentGroupsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_appearance": {
      "post": {
        "operationId": "get_search_appearance",
        "summary": "Search traffic by result kind",
        "description": "Google web search clicks and impressions by search appearance — rich results, videos, FAQ and review snippets, AMP and the other result kinds Search Console reports — two periods compared. Answers 'are our rich results earning clicks' and 'did we lose a result type'. Collected from the day this was added, and back sixteen months once a connection's history has been filled. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchAppearanceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_timeline": {
      "post": {
        "operationId": "get_search_timeline",
        "summary": "Search traffic with what happened",
        "description": "Daily Google search clicks and impressions (and non-branded clicks) beside the client's timeline: deploys, publishes, campaigns and notes, and Google's algorithm updates. searchType reads image, video, news, Discover or Google News instead of web (non-branded clicks are null for the last two, which have no queries). Answers 'what caused this drop' and 'did the release help'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchTimelineInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_annotation": {
      "post": {
        "operationId": "add_annotation",
        "summary": "Note something on the client's timeline",
        "description": "Records something that happened on a day — a deploy, a page published or rewritten, a campaign, a technical change, a note — so traffic charts and get_search_timeline can be read as cause and effect. Answers 'remember that we shipped this today'. Deploy hooks note their runs on their own. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddAnnotationInput"
              },
              "example": {
                "clientId": "client_123",
                "on": "2026-10-01",
                "kind": "deploy",
                "title": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_annotations": {
      "post": {
        "operationId": "list_annotations",
        "summary": "List the client's timeline",
        "description": "The client's timeline notes between two days, oldest first, with Google's algorithm updates when includeGoogle is true. Answers 'what changed around then'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListAnnotationsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_annotations": {
      "post": {
        "operationId": "remove_annotations",
        "summary": "Remove timeline notes",
        "description": "Removes the client's timeline notes by id; unknown ids are ignored. Answers 'take that note off'. Google's updates cannot be removed. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveAnnotationsInput"
              },
              "example": {
                "clientId": "client_123",
                "ids": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_content_profile": {
      "post": {
        "operationId": "get_serp_content_profile",
        "summary": "What the ranking pages have in common",
        "description": "Reads the top Google results for a keyword and each ranking page, and reports what they share: word count range, the outline themes most of them cover, the terms they use and how often, the questions they answer, tables, lists, images, video, schema types, reading ease and how recently they were updated — plus People Also Ask and related searches, and each page's own summary. Results that are not pages to write against — videos and Shorts, forum threads, social posts, app store listings — stay in pages with their reason in excluded, and are listed in excluded as {url, reason}; targetPages counts the rest. Answers 'what does it take to rank for this'. The results page is a paid lookup on the client's account unless someone bought it in the last day (spend says which); the pages are fetched free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpContentProfileInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/build_content_brief": {
      "post": {
        "operationId": "build_content_brief",
        "summary": "Build a content brief",
        "description": "A writer's brief for a keyword (or a cluster: the keyword plus relatedKeywords), built from the pages that rank: search intent and the format that wins (list, how-to, comparison, review, landing page, article), target length, the outline to cover, must-cover and nice-to-have terms, questions to answer (People Also Ask and the ranking pages'), structure and schema to include, the client's own pages to link to and from, and each competing page with what it misses — and ownership, a warning for each keyword the keyword registry already gives another page ('this already belongs to /x'). Also: each competitor scored 1–10 on depth, format, SEO and UX (out of 40), with claude-seo's full excluded list left out as non-competitors (encyclopedias, social and content platforms, search engines, marketplaces, forums, news and media, data platforms, directories, comparison aggregators, job boards, SEO tools, AI platforms, government and academic domains, and tag, author, login, legal and feed paths on any domain), and thinCompetition set when fewer than 3 real competitors remain; a section template for the page type (pageType: service, blog, case_study, category, landing, faq, location, about or homepage; default from the intent) with its goal, sections, schema (never FAQPage) and keyword placement; gaps typed topic, depth or quality with priority = impact × advantage ÷ effort; a required information-gain statement; the E-E-A-T the page needs; words per section; the featured-snippet section and format; title 50–60 and description 130–150 character targets; and with targetUrl, improve mode marking each section keep, strengthen or add against the page as it stands. Answers 'brief me on this keyword' and 'what should this post cover'. save: true keeps it as a research note on the client brief. Same cost as get_serp_content_profile.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuildContentBriefInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/score_content": {
      "post": {
        "operationId": "score_content",
        "summary": "Score a draft before publishing",
        "description": "Scores a draft (a URL, HTML or Markdown) 0–100 against the pages that rank for its keyword: term coverage, outline coverage, questions answered, length and structure — with the missing terms (and how often to use them), missing sections, unanswered questions and a fix list, most important first — factConflicts, sentences stating a price, limit or date that contradicts the client's registered facts; uncitedClaims, the percentages, money and large numbers, 'according to X', 'by 2030' and '3x' figures with no link, footnote or source line within 200 characters (uncitedRatio, a warning above 0.4; a heuristic); invisibleChars, zero-width, bidi and tag characters by codepoint; draftQuality, which only detects and never rewrites: 26 filler and 46 stock AI phrases scored per 1,000 tokens, information density, bigram repetition, flags (filler 50+, AI phrasing 40+, density under 0.20, repetition 30+, under 300 tokens) and a weighted overall; and placement, the keyword in the first 100 words, the URL slug and the front of the title, heading stuffing (more than two subheadings repeating it), average sentence length against 15–20 words, internal links per 1,000 words against 3–5, and a table of contents on pages of 1,500 words or more. Answers 'is this ready to publish' and 'what should I add'. Run it after each revision until it is at par with the results page. Same cost as get_serp_content_profile; a results page bought for the brief is reused free for a day.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreContentInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/cluster_keywords": {
      "post": {
        "operationId": "cluster_keywords",
        "summary": "Group keywords into topics",
        "description": "Groups keywords into topics by how much their Google results overlap: keywords whose top results share at least minShared pages are one topic, which one page should target. Each topic has its parent topic (the highest-volume keyword), total volume, intent, the pages that rank across it, and where the client already ranks. overlap lists keyword pairs by shared top-ten results: 7–10 merge (one page), 4–6 same cluster, 2–3 interlink, 0–1 separate, after leaving out up to the 5 commonest domains that rank on over half the results pages (Wikipedia, Reddit and the like). architecture leaves navigational keywords out and lays the topics out as one pillar (2,500–4,000 words) with 2–5 clusters of 2–4 spokes (1,200–1,800 words), one of eight templates picked by intent and wording (ultimate guide, how-to, listicle, explainer, comparison, review, best-of, landing page), a link matrix {from, to, type, anchor} whose anchors vary so no one carries over 40% of a page's inbound links: spoke ↔ pillar mandatory, 2–3 spoke-to-spoke, at most one cross-cluster, at least 3 inbound per post, every post within 2 clicks of the pillar, 5–21 posts in all, and JSON-LD for the pillar (Article, BreadcrumbList, ItemList of spokes) and each spoke (Article isPartOf the pillar). scorecard checks the client's live pages against it from the latest crawl: no orphans, pillar links 100% both ways, 80% of the planned links present. Answers 'which of these keywords belong on one page' and 'how many pages do we need'. Give keywords (up to 200) or a keyword listId. One results page per keyword, each a paid lookup on the client's account unless someone bought it in the last day — quote with estimate_cost first.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClusterKeywordsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_topic_map": {
      "post": {
        "operationId": "get_topic_map",
        "summary": "Map topics to pages",
        "description": "The client's topics from Search Console (non-branded queries, optionally containing a seed) plus any extra keywords, grouped into clusters and pillars, each mapped to the pages Google shows for it: no_page (write it), one_page, or several_pages (impressions split between pages — merge or fix internal links). Answers 'what should we write next', 'which topics have no page' and 'where are our pages competing'. method serp_overlap clusters by results-page overlap (one paid lookup per keyword unless bought in the last day); search_console clusters by the page each query lands on, free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTopicMapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/compare_crawls": {
      "post": {
        "operationId": "compare_crawls",
        "summary": "What changed since the last crawl",
        "description": "Compares a crawl's issues with the crawl before it (or againstCrawlId), page by page: issues that are new, issues that were fixed, and checks whose count went up (regressed) or down (improved) — a check that flagged a few new pages while clearing more counts as improved — or stayed level with different pages (shifted), each with the pages that came and went — plus pages added, removed and changed. Answers 'did the fixes work', 'what broke this week' and 'what should the weekly audit report'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompareCrawlsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_issue_templates": {
      "post": {
        "operationId": "get_issue_templates",
        "summary": "Issues by template",
        "description": "Groups each issue's pages by URL template (ids, slugs with numbers and query values replaced by *), so '62 pages of /community/es/u/*?sort=*' reads as one fix on one template. Answers 'how many fixes is this really' and 'which template causes this'. ruleId narrows to one issue. indexableOnly (default true) leaves out findings on pages search engines will not index as themselves — noindexed, not answering 200, or canonicalised elsewhere — except the findings that explain why; pass false to see everything. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetIssueTemplatesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_parameter_report": {
      "post": {
        "operationId": "get_parameter_report",
        "summary": "URL parameters and crawl waste",
        "description": "Every query parameter the crawl met — sort orders, filters, tracking, pagination — with how many pages carry it, how many of those are canonicalised to another page (crawl waste), their issues, and whether to strip it from crawls (set_crawl_settings stripParams), keep it, or review it. Answers 'why is the crawl full of ?sort= pages'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetParameterReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_crawl_settings": {
      "post": {
        "operationId": "get_crawl_settings",
        "summary": "How the site is crawled",
        "description": "The client's crawl settings: mode (spider, list or sitemap), include and exclude URL patterns, page and depth limits, the user agent sent and the robots.txt group obeyed, speed (requests per second and concurrency), query parameters stripped from discovered URLs, custom extraction rules, JavaScript rendering (off, shells — only pages that look unrendered — or all, up to renderMaxPages a crawl), whether staging credentials are set (names only, never values), whether requests are signed with Web Bot Auth, and the crawl schedule (cadence, day, UTC hour and nextRunAt; weekly on Monday 02:00 UTC unless set_crawl_schedule changed it). Answers 'what does the crawl do differently for this site'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCrawlSettingsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_crawl_settings": {
      "post": {
        "operationId": "set_crawl_settings",
        "summary": "Change how the site is crawled",
        "description": "Changes the client's crawl settings for the next crawl; fields left out are kept. mode: spider (follow links from the home page and sitemap), list (crawl only listUrls, up to 5,000 addresses on the client's domain) or sitemap (crawl only the sitemap's URLs). includePatterns / excludePatterns: wildcards on the path and query ('/blog/*', '*?sort=*', '/*.pdf') or full addresses — with includes set, only matching URLs are crawled (the home page is still read to find them). maxPages (up to 20,000) and maxDepth (clicks from the start, up to 50). userAgent: preset seolyticize (default), googlebot-smartphone, googlebot-desktop, bingbot, chrome, or custom with your own string; robots.txt is obeyed as that crawler. requestsPerSecond (0.2–10, default 4) and concurrency (1–5); the crawler still backs off on 429s, 5xx and Retry-After. For staging sites' passwords, headers and cookies use set_crawl_auth. stripParams removes query parameters from every discovered URL (names, or prefixes like utm_*), so sorted and filtered copies of a page are crawled once; names match whatever their case (returnTo strips ?returnTo= and ?returnto=), so they are saved lower-cased. extractions reads values off every page (up to 10): css (a selector, optionally an attribute), xpath (//div[@class='author'], //meta[@property='og:type']/@content, (//a)[1]/@href — child and descendant steps, attribute and text tests, positions), regex (first group), jsonld ('Article.datePublished') or meta (a name or property) — see get_extraction_results. render runs JavaScript: off, shells (pages that look unrendered) or all, capped at renderMaxPages. Answers 'crawl this site this way'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetCrawlSettingsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_crawl_auth": {
      "post": {
        "operationId": "set_crawl_auth",
        "summary": "Credentials for crawling a staging site",
        "description": "Lets the crawler into a staging or password-protected site: HTTP basic auth (username and password), custom request headers (e.g. a bypass token for a firewall, up to 10) and cookies ('name=value; other=value'). Replaces whatever was set; clear: true removes it all. Stored encrypted, sent only to the client's own domain (never to a redirect elsewhere or a third-party script), and never shown again — get_crawl_settings lists only the username and header and cookie names. Answers 'audit our staging site' and 'crawl behind the login'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetCrawlAuthInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_page_details": {
      "post": {
        "operationId": "get_page_details",
        "summary": "Everything the crawl read on a page",
        "description": "One crawled page in full: its H2/H3 outline, word count, published and modified dates, structured data as written, custom extraction values, the addresses that redirect to it, its canonical and whether it came from the HTML tag or the HTTP Link header, what JavaScript changed when it was rendered, and its place in the link graph (inlinks, outlinks, click depth, internal PageRank, anchors). Answers 'what does the crawler see on this page'. Use get_page_issues for its issues. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPageDetailsInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_extraction_results": {
      "post": {
        "operationId": "get_extraction_results",
        "summary": "Custom extraction results",
        "description": "The values custom extraction (set_crawl_settings extractions) read off each page in a crawl, page by page; name narrows to one rule. Answers 'which pages have no author', 'what price does each product page show' and 'which posts are older than X'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetExtractionResultsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_rendering_report": {
      "post": {
        "operationId": "get_rendering_report",
        "summary": "What JavaScript changes",
        "description": "Pages the crawl rendered with JavaScript, compared with their raw HTML: words and links that exist only after JavaScript runs, and a title, canonical, meta robots, H1, description or structured data that JavaScript changes — what a search engine or an AI crawler that does not run scripts never sees. Answers 'does our content depend on JavaScript'. Turn rendering on with set_crawl_settings render. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRenderingReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_internal_link_graph": {
      "post": {
        "operationId": "get_internal_link_graph",
        "summary": "The internal link graph",
        "description": "Every crawled page with its internal inlinks and outlinks, clicks from the home page, internal PageRank (0–100), and the anchors it is linked with — plus orphans (indexable pages nothing links to), pages unreachable from the home page, and pages more than three clicks deep. Links that redirect are followed to the page they land on; nofollow links do not count. Answers 'which pages are buried', 'what holds our internal authority' and 'which pages are orphaned'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetInternalLinkGraphInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/suggest_internal_links": {
      "post": {
        "operationId": "suggest_internal_links",
        "summary": "Suggest internal links",
        "description": "Pages that already mention a topic in their text but do not link to the page about it, with the exact sentence and the words to use as the anchor, strongest linking pages first. Give targetUrl (and phrases, default: its title and H1 and the queries it ranks for); without a target, it picks the client's pages in striking distance in Search Console (positions 4–20) — where an internal link moves rankings most. format 'patch' also returns, per page to edit, a unified diff of its HTML or Markdown source (from sources, else the page as served) with the links inserted, and for every link the CMS-ready edit: the words to link, the target and the sentence with the link in it. Answers 'where should we add internal links' and 'give me the edits to make'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuggestInternalLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_anchor_overlap": {
      "post": {
        "operationId": "get_anchor_overlap",
        "summary": "One anchor, several pages",
        "description": "Descriptive anchor texts used for links to more than one page — the site telling search engines that two pages are about the same words, which splits their ranking (cannibalization through links). Generic anchors (read more, click here) are left out. Answers 'are our internal links confusing Google'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAnchorOverlapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_conversions": {
      "post": {
        "operationId": "get_conversions",
        "summary": "Conversions by landing page and source",
        "description": "Conversions (sign-ups, purchases, any goal) by the page a visit landed on, its source or its referrer, with visits, converting visits, conversion rate (of visits with a pageview, null when there are none) and value — and, by landing page, the Search Console queries that bring those visits. Answers 'which pages and queries actually make money' and 'what is organic search worth'. source web_analytics uses the cookieless analytics' custom events (goals: the event names; default the client's event goals, or every event when it has none, which a note says; value from a 'value' property); ga4 uses GA4's key events on organic sessions. channel narrows to search engines or AI assistants. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetConversionsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_conversion_goals": {
      "post": {
        "operationId": "list_conversion_goals",
        "summary": "The events a site sends",
        "description": "The custom events the client's site sends to the cookieless analytics, most-sent first, with how many carry a value — the goals get_conversions can count. Answers 'what are we tracking'. Says how to send one when there are none. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListConversionGoalsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_referring_domains": {
      "post": {
        "operationId": "get_referring_domains",
        "summary": "Referring domains",
        "description": "The domains linking to a domain (the client's or any competitor's), with how many links each sends, whether they follow, the linking domain's authority (0–100) and when the links were first and last seen. Answers 'who links to us', 'who links to them' and 'which sites are worth asking'. source index is free: our own link index (our crawls, client crawls' outlinks, Common Crawl, Bing). auto answers from the index when it holds 50+ links to the domain (or, for referring domains, a complete pass of Common Crawl's domain graph), and otherwise asks the vendor — a paid lookup on the client's account unless anyone bought it in the last week; coverage says which answered. vendor always asks the vendor.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetReferringDomainsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_backlinks": {
      "post": {
        "operationId": "get_backlinks",
        "summary": "Backlinks, new and lost",
        "description": "The links to a domain, page to page, with anchor and follow status; mode new lists links first seen in the last days, lost those no longer seen since. Answers 'which links did we gain or lose this month' and 'what links does this competitor have'. source index is free: our own link index (our crawls, client crawls' outlinks, Common Crawl, Bing). auto answers from the index when it holds 50+ links to the domain (or, for referring domains, a complete pass of Common Crawl's domain graph), and otherwise asks the vendor — a paid lookup on the client's account unless anyone bought it in the last week; coverage says which answered. vendor always asks the vendor.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBacklinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_anchor_distribution": {
      "post": {
        "operationId": "get_anchor_distribution",
        "summary": "Anchor text mix",
        "description": "The anchor texts a domain is linked with, each classed as branded, a bare URL, generic (click here, read more), empty (images) or other (usually keyword-rich), and the mix by referring domains, with bands: each share against its natural range — branded 30–50% (flagged under 15%), URL 15–25%, generic 10–20%, exact match 3–10% (flagged over 15%), partial match 5–15% (flagged over 25%); exact and partial are told apart from other only with moneyTerms, the commercial phrases targeted. Answers 'does our link profile look natural' and 'what do they rank with'. source index is free: our own link index (our crawls, client crawls' outlinks, Common Crawl, Bing). auto answers from the index when it holds 50+ links to the domain (or, for referring domains, a complete pass of Common Crawl's domain graph), and otherwise asks the vendor — a paid lookup on the client's account unless anyone bought it in the last week; coverage says which answered. vendor always asks the vendor.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAnchorDistributionInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_best_pages_by_links": {
      "post": {
        "operationId": "get_best_pages_by_links",
        "summary": "Pages that attract links",
        "description": "A domain's pages by how many domains link to them. Run it on competitors to see what kind of content earns links in a niche — the content worth making. Answers 'what do people link to'. source index is free: our own link index (our crawls, client crawls' outlinks, Common Crawl, Bing). auto answers from the index when it holds 50+ links to the domain (or, for referring domains, a complete pass of Common Crawl's domain graph), and otherwise asks the vendor — a paid lookup on the client's account unless anyone bought it in the last week; coverage says which answered. vendor always asks the vendor.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBestPagesByLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_broken_backlinks": {
      "post": {
        "operationId": "get_broken_backlinks",
        "summary": "Links to broken pages",
        "description": "Links from other sites to the client's pages that no longer work (4xx, or not answering), grouped by page, with the closest live page to redirect each to — links already earned, reclaimed with one redirect. Answers 'which links are we wasting'. Status comes from the latest crawl, and pages it did not crawl are checked. source index is free: our own link index (our crawls, client crawls' outlinks, Common Crawl, Bing). auto answers from the index when it holds 50+ links to the domain (or, for referring domains, a complete pass of Common Crawl's domain graph), and otherwise asks the vendor — a paid lookup on the client's account unless anyone bought it in the last week; coverage says which answered. vendor always asks the vendor.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBrokenBacklinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_competitor_new_pages": {
      "post": {
        "operationId": "get_competitor_new_pages",
        "summary": "What competitors published",
        "description": "New and updated pages on competitors' sites, from their sitemaps (read daily for every competitor a tracker watches, and read now for any not yet watched), grouped by section — 'competitor X published 14 pages under /guides this week'. Answers 'what are they writing about' and 'what did they just launch'. competitors overrides the tracked ones. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCompetitorNewPagesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_competitor_page_changes": {
      "post": {
        "operationId": "get_competitor_page_changes",
        "summary": "Changes to pages that outrank us",
        "description": "Pages that rank above the client for its tracked keywords whose title, H1, length or sections changed — read from snapshots taken every few days. Answers 'what did the page that beat us change'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCompetitorPageChangesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_volatility": {
      "post": {
        "operationId": "get_serp_volatility",
        "summary": "How much the results are moving",
        "description": "How much page one moved between readings for each tracked keyword (0 still, ~10 turned over), a daily index for the client's keywords beside an industry-wide one from every keyword in the archive, and Google's updates in the window. Answers 'is it us or is it Google' when rankings move. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpVolatilityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_overview_citations": {
      "post": {
        "operationId": "get_ai_overview_citations",
        "summary": "Who the AI Overview cites",
        "description": "For each tracked keyword: how often Google showed an AI Overview (or a featured snippet, or People Also Ask — feature), whether the client is cited, who is, and how that changed; plus the domains cited most across the keywords — the outreach and content targets. Answers 'are we in the AI Overview' and 'who does Google trust on this topic'. From the results pages already captured; free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiOverviewCitationsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/describe_datasets": {
      "post": {
        "operationId": "describe_datasets",
        "summary": "What can be queried",
        "description": "The datasets query_data and export_data read — Search Console (every day kept), cookieless analytics events, crawl pages, issues and links, rank captures, backlinks, imported revenue (orders with their channel and landing page), AI assistant visits — with their columns, metrics, time column and how long each is kept. Answers 'what data is there to ask about'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DescribeDatasetsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/query_data": {
      "post": {
        "operationId": "query_data",
        "summary": "Query the stored data",
        "description": "Asks any question of a client's stored data the other tools do not answer: pick a dataset (describe_datasets), group by dimensions, compute metrics (count, sum(col), avg(col), min, max, uniq, plus ctr and position for Search Console, visitors and visits for analytics), filter (eq, neq, contains, starts_with, gt, lt, in, regex), order and limit — or list rows with columns. Search Console can also be grouped or filtered by each query's intent, topic and branded flag. Answers 'which queries containing X lost clicks on mobile in Spain', 'how many 404s per template', 'how are commercial queries trending'. Read-only and always limited to the client's own data. Up to 10,000 rows; export_data for more. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryDataInput"
              },
              "example": {
                "clientId": "client_123",
                "dataset": "gsc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/export_data": {
      "post": {
        "operationId": "export_data",
        "summary": "Export stored data to a file",
        "description": "The same query as query_data, written to a file — CSV, JSON lines or Parquet, up to a million rows — with a download link valid for 24 hours, for BigQuery, a notebook or a spreadsheet. Answers 'give me all of our Search Console history' and 'export the crawl'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportDataInput"
              },
              "example": {
                "clientId": "client_123",
                "dataset": "gsc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_demand_matrix": {
      "post": {
        "operationId": "get_demand_matrix",
        "summary": "Demand for every combination",
        "description": "Search volume, difficulty and CPC for every combination of a pattern's slots — 'receive sms {service} {country}' with services and countries — up to 500, with the client's ranking page and position for each from Search Console and a verdict: write (demand, no page), improve (a page beyond the top ten), have (top ten) or skip (no demand). Answers 'which of these template pages deserve to exist'. Volumes any agency bought before are reused free; the rest is a paid keyword lookup on the client's account, in batches.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDemandMatrixInput"
              },
              "example": {
                "clientId": "client_123",
                "pattern": "example",
                "slots": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ranked_keywords": {
      "post": {
        "operationId": "get_ranked_keywords",
        "summary": "What a domain ranks for",
        "description": "Every keyword a domain, subfolder or page ranks for in Google — position (and the one before), URL, estimated traffic, volume, CPC, difficulty, intent and SERP features — filtered and sorted, paginated. paid: true (or resultType paid) lists the keywords it buys ads on, with the ad; resultType ai_overview_reference lists the keywords whose AI Overview cites it, featured_snippet those where it holds the snippet. change new / up / down lists its recent ranking movements, and lost the keywords it no longer ranks for (with the position it last held). engine amazon reads the keywords an Amazon product ranks for (target its ASIN); engine app_store or google_play the keywords an app ranks for (target the numeric App Store id or the Play package name; US English only) — position, volume and the listing, without the Google-only fields, filters or change. Answers 'what does this competitor rank for', 'which keywords drive their traffic', 'what did they just start ranking for' and 'which searches find this product or app'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRankedKeywordsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_top_pages": {
      "post": {
        "operationId": "get_top_pages",
        "summary": "A domain's pages by traffic",
        "description": "A domain's (or subfolder's) pages ranked by estimated organic traffic, with how many keywords each ranks for, how many in the top 3 and top 10, keywords won and lost, and traffic value. Answers 'which pages bring them their traffic' and 'what content works in this niche'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTopPagesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_domain_overview": {
      "post": {
        "operationId": "get_domain_overview",
        "summary": "A domain's organic and paid standing",
        "description": "For any domain: organic and paid keywords, estimated traffic and its value, the split of positions (top 3, 4–10, 11–100) and keywords new, up, down and lost — in one or more countries (locationCodes, up to 5) — and a monthly history (historyMonths, up to 36). Answers 'how big is this competitor', 'where do they get traffic' and 'is their traffic growing'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDomainOverviewInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_metrics": {
      "post": {
        "operationId": "get_keyword_metrics",
        "summary": "Metrics for a list of keywords",
        "description": "Volume (with 12 months of history), CPC, competition, difficulty, intent and SERP features for up to 700 known keywords — in one or more countries (locationCodes, up to 5), or a city, county or region (locationName, from Google Ads, e.g. 'London,England,United Kingdom'). Countries the research index does not cover are answered from Google Ads. clickstream: true adds clickstream-refined volume (twice the cost). engine bing gives Bing's volume, CPC, competition and history from Bing Ads (English, French and German); engine amazon gives Amazon search volume from DataForSEO Labs (volume only). YouTube publishes no volume and is refused with that reason. Answers 'what is the volume of these keywords', 'how many people search this in Madrid' and 'how often is this searched on Bing or Amazon'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordMetricsInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_backlink_history": {
      "post": {
        "operationId": "get_backlink_history",
        "summary": "A domain's backlinks over time",
        "description": "Month by month for any domain: backlinks, referring domains, new and lost backlinks and referring domains, and rank, from DataForSEO's index (back to 2019; new and lost from May 2021). Answers 'is their link profile growing', 'when did we lose those links'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBacklinkHistoryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_history": {
      "post": {
        "operationId": "get_serp_history",
        "summary": "Who ranked for a keyword over time",
        "description": "Past Google results pages for any keyword (not only tracked ones): for each date, the top results and the features shown. Answers 'who used to rank for this', 'when did this competitor take over' and 'did an update reshuffle this results page'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpHistoryInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_mode_answer": {
      "post": {
        "operationId": "get_ai_mode_answer",
        "summary": "Google AI Mode for a keyword",
        "description": "What Google's AI Mode answers for a keyword, with every source it cites and whether the client is among them. Answers 'are we cited in AI Mode' and 'who does AI Mode trust for this'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiModeAnswerInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_brand_mentions": {
      "post": {
        "operationId": "get_ai_brand_mentions",
        "summary": "Brand share of voice in AI answers",
        "description": "How often AI answers (Google AI Overviews, or ChatGPT) mention or cite each brand — the client and up to 9 competitors, each given as domains and/or brand keywords — across DataForSEO's database of real AI answers, with share of voice, the AI search volume behind the mentions, and the domains cited. No question tracking needed; works for any brand. Answers 'what is our share of voice in AI search' and 'who do AI answers recommend'. Rows carry source: dataforseo (real users' prompts, with AI search volume) or sampled (the client's tracked questions asked by Seolyticize, no volume); the two are never summed. For platforms other than google and chat_gpt only sampled rows exist and the call is free. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost. (about $0.10 a call)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiBrandMentionsInput"
              },
              "example": {
                "clientId": "client_123",
                "brands": [
                  {
                    "name": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_prompt_research": {
      "post": {
        "operationId": "get_ai_prompt_research",
        "summary": "Real questions people ask AI about a topic",
        "description": "Questions real people put to AI assistants that contain a keyword, from DataForSEO's database of AI answers: each with its AI search volume, an excerpt of the answer, the sources cited, the brands named, the follow-up searches the assistant ran (fan-out), and whether the client is cited. Answers 'what do people ask ChatGPT about this' and 'which prompts should we track'. Rows carry source: dataforseo (real users' prompts, with AI search volume) or sampled (the client's tracked questions asked by Seolyticize, no volume); the two are never summed. For platforms other than google and chat_gpt only sampled rows exist and the call is free. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost. (about $0.10 a call)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiPromptResearchInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_search_volume": {
      "post": {
        "operationId": "get_ai_search_volume",
        "summary": "How often a topic is asked of AI",
        "description": "Estimated monthly AI-assistant search volume for up to 1,000 keywords, with 12 months of history. Answers 'how much is this asked in AI search' and 'which topics matter in AI answers'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiSearchVolumeInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_top_cited_domains": {
      "post": {
        "operationId": "get_ai_top_cited_domains",
        "summary": "Who AI answers cite on a topic",
        "description": "The domains AI answers cite most for questions about a topic, with how often and the AI search volume behind it, the client's own marked — the outreach, PR and content targets for AI visibility. Answers 'which sites does AI trust on this topic'. Rows carry source: dataforseo (real users' prompts, with AI search volume) or sampled (the client's tracked questions asked by Seolyticize, no volume); the two are never summed. For platforms other than google and chat_gpt only sampled rows exist and the call is free. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost. (about $0.10 a call)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiTopCitedDomainsInput"
              },
              "example": {
                "clientId": "client_123",
                "topic": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_keyword_advertisers": {
      "post": {
        "operationId": "get_keyword_advertisers",
        "summary": "Who advertises on a keyword",
        "description": "The ads Google shows for a keyword right now: each advertiser's domain, landing page, headline and description, in order. Answers 'who bids on this' and 'what do their ads say'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetKeywordAdvertisersInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_business_profile": {
      "post": {
        "operationId": "update_business_profile",
        "summary": "Change a Google Business Profile listing",
        "description": "Changes the client's own Google Business Profile listing through its connected Business Profile (the connection review replies are posted with): regularHours (the whole week, 24-hour HH:MM, closeDay past midnight), specialHours (holidays and one-off dates, closed or open–close; needs regular hours on the listing), description (up to 750 characters), phone (primary and up to two additional), website, categories (Google ids such as gcid:dentist; primary and up to nine additional) and simple yes/no attributes by Google id. Only the fields given are changed (locations.patch with an updateMask; attributes through updateAttributes); phone and category lists Google replaces whole keep the half not given from the listing. dryRun: true changes nothing and returns the exact patch and updateMask, the listing's fields before and after, and Google's own check of the change (validateOnly) — show it to the person first. Refused with missing_scope when the connection was not granted permission to manage the listing, and not_connected when the location has none; next says how to connect it. Google may hold a change for review before it shows. Answers 'update our opening hours' and 'change the business description'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBusinessProfileInput"
              },
              "example": {
                "clientId": "client_123",
                "changes": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_business_post": {
      "post": {
        "operationId": "create_business_post",
        "summary": "Publish a Google Business Profile post",
        "description": "Publishes an update post (topic STANDARD) on the client's own Google Business Profile listing through its connected Business Profile: summary (up to 1,500 characters) and an optional callToAction — BOOK, ORDER, SHOP, LEARN_MORE or SIGN_UP with a url, or CALL with none (it dials the listing's phone). dryRun: true publishes nothing and returns the exact localPosts body. The answer carries Google's name for the post and its state (PROCESSING until Google has reviewed it, LIVE, or REJECTED for its content policy). Refused with missing_scope or not_connected as update_business_profile is. get_business_posts reads the posts already there. Answers 'post this offer on our Google listing'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBusinessPostInput"
              },
              "example": {
                "clientId": "client_123",
                "summary": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_hreflang_parity": {
      "post": {
        "operationId": "get_hreflang_parity",
        "summary": "Are the language versions real translations",
        "description": "Reads each language version of the client's pages (the groups the crawl's hreflang or /es/-style paths tie together) and scores every pair against its source 0–100: equal H2 and H3 counts; title, meta description and schema inLanguage actually localised (the language detected, not just declared); length within the band the language should take (German 25–35% longer than English, Japanese 10–25% shorter, in words); a stale translation (modified before its source); numbers, dates, prices and phone numbers written for the locale; and source-language sentences left untranslated. Unmeasured parts are null and the rest rescale. Each pair also carries a cultural adaptation check against its market's profile (DACH, Francophone, Hispanic, Japanese: formal address, hard-sell CTAs, Impressum or Mentions légales, local number, date and currency formats, US brands, statistics and laws, length against English), each failure a Medium 'Cultural Adaptation' finding, and machine-translation QA (body identical to the source, <html lang> against the detected language, a translated meta description over 160 characters, schema inLanguage, Google's translate widget). contentParity scores each group 30/30/25/15: the page exists in every declared language, title, meta and schema localised, structure (sections ±1, images and charts exact, FAQ items ±2), and freshness (≤7, 8–30, 31–90, 90+ days behind). A heuristic, and it says so. url picks the group containing that page; sourceLang which version the others are measured against (default the x-default one). Answers 'is our German site actually translated' and 'which translations are out of date'. Free: fetches the client's own pages.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetHreflangParityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/generate_hreflang": {
      "post": {
        "operationId": "generate_hreflang",
        "summary": "Write the hreflang for the site",
        "description": "Generates hreflang for every group of language versions in a crawl (tied by existing hreflang, or the same path under a language prefix such as /es/ or /de-at/), each with a self-reference and an x-default (xDefault names the fallback language; default the language of the unprefixed pages): <link> tags for groups under 50 versions, a Link HTTP header for PDFs, and an xhtml:link sitemap for groups of 50 or more (method forces one). Lists groups with two pages claiming one language, and pages whose language could not be told. Answers 'write our hreflang tags' and 'give me an hreflang sitemap'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateHreflangInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_sxo_gap": {
      "post": {
        "operationId": "get_sxo_gap",
        "summary": "Is this the kind of page Google ranks here",
        "description": "Classifies the client's page and the top 10 results for its keyword into claude-seo's eight types (tool, local, comparison, product, landing, service, hybrid, else blog, in that order of precedence) and says how strongly Google agrees on one type (over 60% strong, 40–60% mixed, under 40% fragmented) and how bad the page's mismatch is, from an explicit page × results table (a blog where products, tools, local pages or landing pages rank is critical; a blog against comparisons high; a landing page where tools rank high), and which of the expected type's required elements the page has. A 0–100 gap score against the ranking pages: page type, depth, UX, schema, media and authority 15 each, freshness 10 (null parts drop out). keyword defaults to what the title and H1 share, else the page's top Search Console query. wireframe: true adds the page's sections now, the target outline and the target layout for the page type the results want (landing, blog, product, comparison, service, local, tool or hybrid; free); deep: true reads UX from the page rendered on a phone (H1 and CTA above the fold, tap targets, font size, overlaps, overlays) and authority from its E-E-A-T score beside domain authority, and rescores (free, slower); personas: true adds 4–7 searchers from People Also Ask, ads and related searches, each a full card (role, goal, emotional state, journey stage, key questions, intent) scored on relevance, clarity, trust and action (25 each) and rated 80 excellent, 60 good, 40 needs work, below a critical mismatch, a persona score weighted by each intent's share of the results, and 3–5 user stories ('As a …, I want to …, because …, but I'm blocked by …') with their evidence, from one metered Claude call. A heuristic, and it says so. Answers 'why doesn't this page rank' and 'what kind of page does Google want for this'. The results page is a paid lookup unless bought in the last day; quote with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSxoGapInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/build_comparison_page": {
      "post": {
        "operationId": "build_comparison_page",
        "summary": "Build a comparison page",
        "description": "Plans an honest comparison page — vs (the client against one rival), alternatives (to the first competitor), roundup (best tools in a category) or table — from what each product publishes: its pricing and feature pages (and any sourceUrls) are read and a feature matrix filled, each cell ✅, ⚠️ partial, ❌ or 'Not publicly available' with its source URL, and every price 'as of' the read. Gives the title from the pageType's template, an H1 under 70 characters, a sourced outline of at least 1,500 words with calls to action above the fold, after the table and at the end (never inside a competitor's section), each competitor's strengths acknowledged, the client's product named as the client's, JSON-LD (SoftwareApplication with offers; ItemList in ranked order for roundups; no AggregateRating without real review data) checked against Google's requirements; each product's hidden costs from its pricing page (setup fees, per-user pricing, overages, transaction fees, annual-only billing, minimum seats), a 'Last updated' stamp, related comparisons to link, and checks that the outline carries a methodology section, the hidden costs and related comparisons; and the comparison searches by pattern ('[a] vs [b]', '[a] vs [b] pricing', 'is [a] better than [b]', '[a] alternatives', '[a] alternatives [year]', '[a] review [year]', 'best [category] tools', '[category] comparison'), with demand: true their volumes (one paid keyword-metrics read). Answers 'write a vs page against our rival' and 'what should our alternatives page say'. The outline is one metered Claude call; quote with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuildComparisonPageInput"
              },
              "example": {
                "clientId": "client_123",
                "pageType": "vs",
                "competitors": [
                  {
                    "name": "example",
                    "domain": "example.com"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_keyword_owners": {
      "post": {
        "operationId": "set_keyword_owners",
        "summary": "Say which page owns a keyword",
        "description": "Registers the page that owns each keyword (or cluster: the keyword plus its cluster members) for the client, replacing an earlier claim on the same keyword. build_content_brief and draft_article then warn when a piece would compete with the owner, and get_cannibalization says which page should win. Accept propose_keyword_owners' proposals with source search_console. dryRun: true saves nothing and lists wouldSet, each claim as it would be saved with the claim it would replace. Answers 'make /pricing the page for \"crm pricing\"'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetKeywordOwnersInput"
              },
              "example": {
                "clientId": "client_123",
                "owners": [
                  {
                    "keyword": "carrier lookup",
                    "url": "https://example.com/page"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_keyword_owners": {
      "post": {
        "operationId": "list_keyword_owners",
        "summary": "Which page owns which keyword",
        "description": "The client's keyword-to-page registry: each keyword (with its cluster) and the page that owns it, optionally for one page. Answers 'which keywords is /blog/x meant to rank for' and 'who owns this query'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListKeywordOwnersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_keyword_owners": {
      "post": {
        "operationId": "remove_keyword_owners",
        "summary": "Release keywords from the registry",
        "description": "Removes the registry's claims on the given keywords; unknown keywords are ignored. Answers 'that keyword no longer belongs to that page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveKeywordOwnersInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/propose_keyword_owners": {
      "post": {
        "operationId": "propose_keyword_owners",
        "summary": "Propose an owner page for each query cluster",
        "description": "Groups the client's non-branded Search Console queries by the page they land on most and proposes, for each cluster, the page Search Console sends the most clicks to (impressions when none has clicks): its share of the cluster's clicks, the other pages competing, whether it is already registered (and to which page), and confidence clear, split (the clicks are divided: cannibalization) or thin. Nothing is saved: accept with set_keyword_owners. Answers 'which page should own each topic'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProposeKeywordOwnersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_topical_authority": {
      "post": {
        "operationId": "get_topical_authority",
        "summary": "How strong the site is on each topic",
        "description": "A 0–100 topical authority score per topic (the topic map's pillars, from Search Console): coverage (the share of the topic's query clusters with a page ranking in the top 20) × rankings (impression-weighted) × internal links (links into each covering page, from the latest crawl) — each part given — and the next three pages that would raise it most: write (a cluster nothing covers), improve (a page beyond the first page) or link (a weakly linked page). extraKeywords adds topics the site does not rank for yet. Answers 'where are we an authority' and 'what should we write next to own this topic'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTopicalAuthorityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_entity_coverage": {
      "post": {
        "operationId": "get_entity_coverage",
        "summary": "The entities a page should cover",
        "description": "The named entities (people, products, places, organisations, concepts) at least two of the ranking pages for a keyword cover, from their capitalised phrases, each resolved on Wikidata (resolve: true, free), whether the client's page (url, html or markdown; or none, to plan one) names it, a 0–100 coverage score, and the JSON-LD to add: about (the main entity) and mentions, with sameAs links to Wikidata and Wikipedia. Answers 'which entities does our page miss' and 'what sameAs and about schema should it carry'. Same cost as get_serp_content_profile.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetEntityCoverageInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_freshness_queue": {
      "post": {
        "operationId": "get_freshness_queue",
        "summary": "Pages to refresh first",
        "description": "The client's pages ranked by Search Console clicks at risk (a month's clicks, weighted by how many stale signals the page shows and doubled when it is already losing them) from going stale: the results page for its top query moved to newer content (the ranking pages' stored dates, at the median, over six months newer than the page's own), a past year in the title, past years in the text (with the sentence), a price or limit contradicting the client's registered facts, or no date on a page whose rivals are recent. Each with its reasons and priority. Answers 'what should we update this month'. Free: stored results pages and the latest crawl only.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetFreshnessQueueInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_programmatic_pages": {
      "post": {
        "operationId": "check_programmatic_pages",
        "summary": "Do the template pages earn their place",
        "description": "Finds the site's template pages (the same path with one variable segment, minVariants or more of them; or one template given as a glob such as /sms/*) in a crawl and, for every variant: how much of its text is its own (the share no more than a third of its siblings repeat) and how close its nearest sibling is (simhash bits), whether it is thin against the template's median, and its demand (Search Console clicks and impressions over 90 days, stored search volume for its H1) — with a verdict: keep, merge (all but a duplicate of a sibling with more demand: fold it in) or noindex (thin or boilerplate, and no demand). Each template also gets checks with six 0–100 sub-scores (data, template uniqueness, URL, linking, thin risk, index management; null where unmeasured): a gate (100+ unreviewed pages is a warning, 500+ says stop), thin content (under 40% own text is thin, under 30% fails, under 300 words flagged), descriptions that open with the title, end on a stock call to action or share one shape with the name swapped in, URL rules (lowercase, hyphens, under 100 characters, no query string, one trailing-slash style, no duplicate slugs), links to 3–5 siblings, self-referencing canonicals, and Google's indexing (URL Inspection) against the pages meant to be indexed. checks.extras adds near-duplicate records (title, H1 and description sharing more than 80% of their words), boilerplate (pages whose copy is over 60% words most of the template's pages share), a review sample of 5% of the template, thinnest first (up to 10% is better), noindexed variants the sitemaps still list, and a crawl-budget notice past 10,000 pages. Answers 'which of our location pages should exist' and 'are these programmatic pages thin'. For the demand of combinations not yet built, use get_demand_matrix. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckProgrammaticPagesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_snippet_targets": {
      "post": {
        "operationId": "get_snippet_targets",
        "summary": "Featured snippets within reach",
        "description": "Queries where Google shows a featured snippet or People Also Ask and the client ranks 2–10 (Search Console, last 28 days), from the stored results pages (readMissing: true buys the ones not stored): who holds the snippet, the format to win it — a paragraph of about 45 words, a list or a table — and, with draft: true, a draft in that format from one metered Claude call for the batch. Answers 'which snippets can we steal' and 'write the answer box for this query'. Paid only for drafts and missing results pages; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSnippetTargetsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/plan_content": {
      "post": {
        "operationId": "plan_content",
        "summary": "Plan the editorial calendar",
        "description": "Builds and stores an editorial calendar for the coming months at a cadence (weekly ≈ 4 a month, fortnightly 2, monthly 1, or a number a month) from the topic map (Search Console clusters with no strong page: write; clusters on page two: refresh), extraKeywords not yet covered, the keyword registry (a keyword another page owns becomes a refresh of that page, never a second page), and seasonality (stored monthly volumes; trends: true reads Google Trends for the top items, paid): seasonal pieces land two months before their peak, the rest in order of value. Each item carries its keyword and cluster, ready-made build_content_brief arguments, target URL, internal links to add (to and from), search volume, estimated monthly clicks at position 3 and their value (clicks × CPC). hubs lays each pillar with three or more clusters out as a hub — one pillar (2,500–4,000 words), 2–5 clusters of 2–4 spokes (1,200–1,800 words), templates by intent, a link matrix (spoke ↔ pillar mandatory, 2–3 spoke-to-spoke, at most one cross-cluster) — and scores the live site's links against it: no orphans, pillar links both ways, 80% of planned links present. Answers 'what should we publish over the next quarter'. Read back with list_content_plan; change items with update_content_plan_item.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanContentInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_content_plan": {
      "post": {
        "operationId": "list_content_plan",
        "summary": "List the editorial calendar",
        "description": "The client's planned content, month by month: keyword, kind (new or refresh), target URL, status, brief arguments, internal links and estimated value. Filter by month range, status or one plan. Answers 'what is planned for next month'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListContentPlanInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_content_plan_item": {
      "post": {
        "operationId": "update_content_plan_item",
        "summary": "Change a planned piece",
        "description": "Moves a planned piece to another month or date, changes its status (planned, briefed, drafting, published, dropped), target URL, keyword or notes. Answers 'mark that article published' and 'push this to May'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContentPlanItemInput"
              },
              "example": {
                "clientId": "client_123",
                "id": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_referrals": {
      "post": {
        "operationId": "get_ai_referrals",
        "summary": "Visits AI assistants send",
        "description": "Visits from AI assistants — ChatGPT (chatgpt.com, chat.openai.com), Perplexity, Gemini, Copilot, Claude, Google AI Mode (where the referrer shows it), Grok, Meta AI, DeepSeek and others — as an AI channel: from the cookieless analytics, visits by assistant, their share of all visits, the landing pages they arrive on and the conversions they bring (goal events); from GA4, sessions by source / medium, landing pages and key events and revenue for the same sources. Answers 'how much traffic does ChatGPT send us', 'which pages do assistants send people to' and 'do AI visitors convert'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiReferralsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_citation_history": {
      "post": {
        "operationId": "get_ai_citation_history",
        "summary": "Which of our pages assistants cite, over time",
        "description": "The client's pages cited in the tracked questions' AI answers over the last N days: per page, how many answers cited it, by which assistants, for which questions, first and last seen, and citations per week — and, per question and assistant, the pages gained and lost between its last two checks. Answers 'which pages does ChatGPT cite', 'did we lose a citation this week' and 'which content earns AI citations'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiCitationHistoryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_answer_share": {
      "post": {
        "operationId": "get_ai_answer_share",
        "summary": "Share of AI answers per topic, week by week",
        "description": "For each topic of the tracked questions, week by week across assistants (or one): how many answers there were, how many mentioned or cited the client, its share of answers, and its share of every tracked brand's mentions in them (share of voice). Answers 'are we winning the pricing questions in ChatGPT' and 'is our AI share growing by topic'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiAnswerShareInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_crawler_access": {
      "post": {
        "operationId": "get_ai_crawler_access",
        "summary": "Can each AI crawler reach and read the pages that matter",
        "description": "Per AI agent — GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, Claude-User, PerplexityBot, Perplexity-User, Google-Extended, Applebot-Extended, Meta-ExternalAgent, CCBot — for the client's top pages by Search Console clicks: which robots.txt allows and blocks, whether the server or CDN turns it away when the homepage is fetched under its name, which pages need JavaScript to show their content (from the crawl's rendering, which AI crawlers do not do), and, given an access log, how often it came, how many pages it read and how many requests failed. A verdict (open, partial, blocked) and fixes per agent, its purpose (training, search, user) said. Answers 'can ChatGPT read our site' and 'are we blocking AI search by accident'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiCrawlerAccessInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_answer_readiness": {
      "post": {
        "operationId": "check_answer_readiness",
        "summary": "Is the page written to be quoted by assistants",
        "description": "Checks pages of the client's site for what makes an assistant quote them: a direct answer in the first 100 words (not a preamble), a plain definition, sourced claims (links to sources outside the site, against the figures stated), a named author, a published or updated date, and structured data — a 0–100 score and a fix list per page, and the site's fixes in order of how many pages need them. Give urls, or check the top pages by Search Console clicks (topPages). Answers 'why is this page not cited' and 'how do we make our pages answer-ready'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckAnswerReadinessInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_client_facts": {
      "post": {
        "operationId": "set_client_facts",
        "summary": "Record the client's canonical facts",
        "description": "Writes the client's facts — prices, plan limits, countries served, founding date, contact details — each with a key (\"starter plan price\"), its value (\"$29/month\"), a category and optionally the terms a sentence must contain to be about it; replaces a fact with the same key. Keys are case-insensitive and stored folded (lowercase, single spaces): \"Free plan limits\" is saved and listed as \"free plan limits\", and the answer gives each key as stored, so compare keys folded. dryRun: true saves nothing and lists wouldSet, each fact as it would be saved with the value it would replace. check_ai_brand_accuracy checks assistants against them first, and score_content and get_freshness_queue flag pages whose text contradicts one. Answers 'remember that our price is now $29'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetClientFactsInput"
              },
              "example": {
                "clientId": "client_123",
                "facts": [
                  {
                    "key": "example",
                    "value": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/import_client_facts": {
      "post": {
        "operationId": "import_client_facts",
        "summary": "Import the client's facts from a manifest",
        "description": "Reads a facts manifest the site's repository owns — JSON {\"facts\": [{key, value, category?, terms?, sourceUrl?}]}, the same fields as set_client_facts — and writes it with set_client_facts, so the facts live next to the code they describe. From content given, from url, or by default from https://<client domain>/.well-known/seolyticize.json. dryRun: true shows what would change (wouldSet, each with what it replaces) and writes nothing. Each deploy hook call compares the published manifest with the registered facts and lists differences as factsDrift. Answers 'keep our facts in sync with the repo'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportClientFactsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_client_facts": {
      "post": {
        "operationId": "list_client_facts",
        "summary": "List the client's canonical facts",
        "description": "The client's registered facts by category: key, value, terms and source. Answers 'what do we hold as true about this client'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListClientFactsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/remove_client_facts": {
      "post": {
        "operationId": "remove_client_facts",
        "summary": "Remove facts from the registry",
        "description": "Removes the client's facts by key; unknown keys are ignored. Answers 'forget the old enterprise price'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RemoveClientFactsInput"
              },
              "example": {
                "clientId": "client_123",
                "keys": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_llm_responses": {
      "post": {
        "operationId": "get_llm_responses",
        "summary": "Ask ChatGPT, Claude, Gemini and Perplexity through DataForSEO",
        "description": "Asks one question (up to 500 characters) live on the chosen models through DataForSEO — chat_gpt, claude, gemini, perplexity, and chat_gpt_app: the ChatGPT app itself as a person sees it, with the sources it cited and the searches it ran (about $0.004) — with web search on by default, and returns each answer's text, the pages it cited, the follow-up searches it ran (fanOutQueries, where the platform reports them), and which of the client's tracked brands it named and whether the client was named and cited. Needs no assistant keys of the agency's own; nothing is stored. Use it to explore a question before tracking it. Answers 'what do the big models say when asked this' and 'what does ChatGPT search for to answer it'. A paid lookup on the client's account unless anyone asked the same thing recently (served says which); quote it with estimate_cost. (one purchase per model; about $0.01–0.10 each with web search)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLlmResponsesInput"
              },
              "example": {
                "clientId": "client_123",
                "prompt": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/suggest_ai_visibility_setup": {
      "post": {
        "operationId": "suggest_ai_visibility_setup",
        "summary": "Set up AI visibility from the client's own data",
        "description": "Drafts a client's AI visibility setup: its own brand (from the client's name, site and brand terms), competitors (from the brief and rank tracker, then DataForSEO's organic competitors to fill up to maxCompetitors), and starter questions grouped by topic — real questions people ask AI assistants, from DataForSEO's AI answer index, around the seed keywords (given, or the tracked keywords with the most AI search volume), each with its AI search volume and fan-out searches, branded or neutral. Nothing is saved unless apply is true, which adds them all (topics included) as save_ai_visibility_setup would, skipping anything already tracked. Answers 'set up AI tracking for this client'. A paid lookup on the client's account unless anyone asked the same thing recently (served says which); quote it with estimate_cost. (up to one competitors read, one AI volume read and one question read per seed)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuggestAiVisibilitySetupInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_business_profile": {
      "post": {
        "operationId": "get_business_profile",
        "summary": "Any business's Google profile",
        "description": "The Google Business Profile of any business, found by name or by cid / place_id: categories, address, phone, site, coordinates, rating and its spread, review count, hours, attributes, photos, whether it is claimed, the topics reviewers mention and the businesses people also search. Gives the place_id and coordinates add_local_location needs. Answers 'what does this competitor's listing have that ours lacks'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBusinessProfileInput"
              },
              "example": {
                "clientId": "client_123",
                "business": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/search_local_businesses": {
      "post": {
        "operationId": "search_local_businesses",
        "summary": "Businesses in an area",
        "description": "Every Google Maps business within a radius of a point, by category and/or name, with rating, reviews, claimed status, photos, site and ids — up to 1,000. Answers 'who are all the plumbers within 10 km' and 'which rivals have unclaimed listings'. Category names are Google's (dentist, plumber, pizza_restaurant); get_local_categories lists those in an area. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchLocalBusinessesInput"
              },
              "example": {
                "clientId": "client_123",
                "lat": -90,
                "lng": -180
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_business_questions": {
      "post": {
        "operationId": "get_business_questions",
        "summary": "A business's Google Q&A",
        "description": "The questions people asked on any business's Google listing, with the answers and who gave them, and how many are unanswered. Answers 'what do customers ask about us' and 'which questions should we answer on our profile'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBusinessQuestionsInput"
              },
              "example": {
                "clientId": "client_123",
                "business": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_local_categories": {
      "post": {
        "operationId": "get_local_categories",
        "summary": "Business categories in an area",
        "description": "The Google business categories used around a point, with how many businesses use each, and the attributes common among them — the categories a listing should name, and the gaps. Narrow it with categories to see what businesses in those also list. Answers 'which secondary categories do the dentists here use'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLocalCategoriesInput"
              },
              "example": {
                "clientId": "client_123",
                "lat": -90,
                "lng": -180
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_maps_results": {
      "post": {
        "operationId": "get_maps_results",
        "summary": "Google Maps results from one spot",
        "description": "The Google Maps (or Local Finder) results for a keyword as searched from one point — or the client's country — with every business's rating, reviews, category, site and ids, and where the client sits. One lookup, where a grid scan is many. Answers 'who shows on the map for this from downtown'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetMapsResultsInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_business_reviews": {
      "post": {
        "operationId": "get_business_reviews",
        "summary": "Any business's Google reviews",
        "description": "Google reviews of any business (up to 500, newest first) with the rating, text, date, author and whether the owner replied. Collecting takes a minute or two: the first call (with business) queues it and returns a taskId — that call is the paid one — and calling again with the taskId collects it for free (status pending until ready). For the client's own locations, sync_local_reviews keeps them stored. Answers 'what do customers complain about at this competitor'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBusinessReviewsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_business_posts": {
      "post": {
        "operationId": "get_business_posts",
        "summary": "Any business's Google posts",
        "description": "The posts (updates, offers, events) any business has published on its Google Business Profile, newest first: text, date, image, links and the post's address, with how many there are, when the latest went up and how many in the last 90 days. Collecting takes a few minutes: the first call (with business) queues it and returns a taskId — that call is the paid one — and calling again with the taskId collects it for free (status pending until ready). Answers 'how often does this competitor post on Google' and 'what are they promoting'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBusinessPostsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_platform_reviews": {
      "post": {
        "operationId": "get_platform_reviews",
        "summary": "A business's Tripadvisor or Trustpilot reviews",
        "description": "Reviews of a business on Tripadvisor (business: its name and town, or a Tripadvisor URL path such as /Restaurant_Review-g…) or Trustpilot (business: its domain), newest first, with the platform's own rating and review count, the star spread over the reviews read, the average and the owner's response rate — for the cross-platform comparison beside Google's reviews (get_business_reviews, sync_local_reviews). Both are queued: the first call (with business) is the paid one and returns a taskId; calling again with the taskId collects it for free (status pending until ready). Answers 'how are we rated on Tripadvisor' and 'what does Trustpilot say about this competitor'. A paid lookup on the client's account unless anyone read the same thing recently; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPlatformReviewsInput"
              },
              "example": {
                "clientId": "client_123",
                "platform": "tripadvisor"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/search_locations": {
      "post": {
        "operationId": "search_locations",
        "summary": "Find a location to track from",
        "description": "Looks up search locations in a country by name — cities, counties, regions, DMAs, postal areas — with the location code create_rank_tracker and the research tools take. Answers 'track us from Manchester, not all of the UK'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchLocationsInput"
              },
              "example": {
                "clientId": "client_123",
                "query": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_landing_pages": {
      "post": {
        "operationId": "get_landing_pages",
        "summary": "Which pages the tracked keywords land on",
        "description": "For a rank tracker's latest captures: each of the client's pages with how many tracked keywords it ranks for, how many in the top 3 and top 10, its average position and best keyword — and the keywords where two or more of its pages compete. Answers 'which pages carry our rankings' and 'where are we cannibalising'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLandingPagesInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_tracker_ai_mode": {
      "post": {
        "operationId": "get_tracker_ai_mode",
        "summary": "AI Mode beside each ranking",
        "description": "Reads Google AI Mode for a tracker's keywords (up to limit) and puts beside each latest position whether AI Mode cites the client and which domains it cites — the gap between ranking and being the answer. One paid AI Mode read per keyword: quote it with estimate_cost first. Answers 'we rank for these, but does AI Mode cite us'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTrackerAiModeInput"
              },
              "example": {
                "clientId": "client_123",
                "trackerId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_audit_performance": {
      "post": {
        "operationId": "get_audit_performance",
        "summary": "Speed in the audit",
        "description": "How fast the audited site is, as recorded when the crawl finished. Lab: a Lighthouse run (mobile) of the homepage and one page of each of the largest URL templates, with performance, accessibility, SEO and best-practices scores (0–100), LCP, TBT and CLS — one synthetic load each, from a Google datacentre. Field: the origin's Core Web Vitals from the Chrome UX Report — LCP, INP and CLS at the 75th percentile of real visits over 28 days, per phone and desktop, graded and with Google's pass/fail. Each page also carries diagnostics (where the time went: the LCP element and its subparts — TTFB, resource load delay, resource load duration, element render delay — DOM size, long tasks, main-thread work by kind, script execution, render-blocking requests, unused JavaScript and CSS, third parties, and the INP breakdown when the run interacted, which a PageSpeed run never does), and lab.fixes merges the pages' findings into one list ranked by estimated saving, with the pages each affects. Missing figures say why (no key, too few visits). crawlId defaults to the latest complete crawl. Answers 'is the site fast', 'which template is slow', 'what should we fix first for speed' and 'do we pass Core Web Vitals'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAuditPerformanceInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/run_audit_performance_sample": {
      "post": {
        "operationId": "run_audit_performance_sample",
        "summary": "Measure the audit's speed again",
        "description": "Takes the latest complete audit's speed sample again, in the background: a Lighthouse run (mobile) of the homepage and one page of each of the largest URL templates (up to 5 pages), and the origin's Chrome UX Report reading for phone and desktop — the same sample an audit takes when it finishes, replacing that audit's figures. For an audit that finished before a PageSpeed Insights key was connected, or whose runs failed. Takes a few minutes; read the result with get_audit_performance. Uses the agency's PageSpeed Insights and Chrome UX Report connections. Answers 'measure the site's speed now'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunAuditPerformanceSampleInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/plan_redirect_map": {
      "post": {
        "operationId": "plan_redirect_map",
        "summary": "Redirect map for a migration",
        "description": "Proposes a 1:1 301 redirect for each old address of a site migration, onto the page of the new site's crawl (newCrawlId, default latest) that most plausibly replaced it, with a confidence (0–1) and the evidence: the new site already redirects it, the same path (also ignoring case, slashes and .html/.php), the same text, or similar path words, title and text; failing those the nearest surviving section, and only then the homepage (flagged: Google treats mass homepage redirects as soft 404s). Give exactly one old source: oldUrls (a list), oldSitemapUrl (the old site's sitemap) or oldCrawlId (an earlier crawl of this client — best, since titles and text are compared too). format csv, htaccess (exact-match RewriteRules) or nginx (a map block) returns the whole map as a file in content. Answers 'where should each old URL redirect'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanRedirectMapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/simulate_serp_snippet": {
      "post": {
        "operationId": "simulate_serp_snippet",
        "summary": "How a result will look",
        "description": "Shows a page's title and meta description as Google's results would, measured in pixels rather than characters: what is shown and where it is cut with an ellipsis on desktop and on mobile, the breadcrumb URL, and warnings (cut, too short to survive Google's rewriting, missing — with what Google falls back to). Give url to read the live page, and/or title and description to try new wording (given text overrides the page's). Widths are approximations of Google's layout. Answers 'will this title be truncated' and 'what will this look like in Google'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SimulateSerpSnippetInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/invite_team_member": {
      "post": {
        "operationId": "invite_team_member",
        "summary": "Invite someone to the team by email",
        "description": "Emails an invitation to join the agency with a role — admin, manager, analyst or client_viewer — optionally limited to some clients. Unlike add_team_member the person need not have an account yet: they sign up or sign in, as the invited address, and the link makes them a member. The link lasts 7 days and works once. Answers 'invite sam@agency.com as an analyst on Acme'. Returns the invite, whether the email was sent, and the link itself for passing on by hand. Refused for an existing member, an address with a live invite (use resend_team_invite), or a client outside the caller's reach.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteTeamMemberInput"
              },
              "example": {
                "email": "name@example.com",
                "role": "admin"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_team_invites": {
      "post": {
        "operationId": "list_team_invites",
        "summary": "List pending invites",
        "description": "Invites not yet accepted or withdrawn, newest first, with role, client scope, when each expires and how often it was sent. Expired ones are listed so they can be resent. Answers 'who have we invited who has not joined'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListTeamInvitesInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/resend_team_invite": {
      "post": {
        "operationId": "resend_team_invite",
        "summary": "Resend an invite",
        "description": "Sends an invite again with a new link and a fresh 7 days; the old link stops working. By the inviteId list_team_invites gives. At most 5 sends per invite and one a minute. Answers 'they never got the email'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendTeamInviteInput"
              },
              "example": {
                "inviteId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_team_invite": {
      "post": {
        "operationId": "revoke_team_invite",
        "summary": "Withdraw an invite",
        "description": "Withdraws an invite so its link no longer works. Answers 'cancel the invite to sam@'. Safe to repeat: revoked is false when it was already used or withdrawn.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "member:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeTeamInviteInput"
              },
              "example": {
                "inviteId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_tasks": {
      "post": {
        "operationId": "list_tasks",
        "summary": "List a client's tasks",
        "description": "A client's tasks, open ones first and soonest due first: title, status, assignee, due date, whether overdue, and the issue, page or keyword each is about. Answers 'what is left to do for Acme' and 'what is Sam working on'. Filter by status and assignee. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListTasksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_task": {
      "post": {
        "operationId": "create_task",
        "summary": "Add a task",
        "description": "Adds a task to a client's list, optionally assigned, dated and linked to an audit issue, a page or a keyword. Answers 'remind us to rewrite the pricing page by Friday'. One open task per audit issue: a second is refused while the first is open.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskInput"
              },
              "example": {
                "clientId": "client_123",
                "title": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_task": {
      "post": {
        "operationId": "update_task",
        "summary": "Change a task",
        "description": "Changes a task's title, notes, status, assignee, due date or link; only what is passed changes, and null clears. Moving to done or wont_do records when; moving back to todo clears it. Answers 'mark the title fixes done' and 'give this to Sam for next week'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskInput"
              },
              "example": {
                "clientId": "client_123",
                "taskId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_task": {
      "post": {
        "operationId": "delete_task",
        "summary": "Delete a task",
        "description": "Deletes a task outright. Prefer update_task with status wont_do, which keeps the record. Answers 'remove that task'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteTaskInput"
              },
              "example": {
                "clientId": "client_123",
                "taskId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_tasks_from_audit": {
      "post": {
        "operationId": "create_tasks_from_audit",
        "summary": "Turn audit issues into tasks",
        "description": "Makes one task per issue a crawl found — titled from the issue, with its page count and howToFix in the notes — for the chosen rule ids or every issue of the chosen severities (default critical and warning). Issues that already have an open task are skipped, so this is safe after every crawl. Findings accepted as intentional (accept_issue) are left out, and an issue they cover entirely makes no task. With path owners set (set_path_owners), each task names the owner of most of its pages, and its notes say how the pages split between owners. crawlId defaults to the latest completed crawl. dryRun: true makes nothing and lists wouldCreate (each task's title, notes, assignee and due date) and skipped. Answers 'put the audit on our to-do list'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTasksFromAuditInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_portfolios": {
      "post": {
        "operationId": "list_portfolios",
        "summary": "List portfolios",
        "description": "The agency's portfolios — named groups of clients or single sites — with their members. A viewer limited to some clients sees only their members, with a count of the rest. Answers 'which client groups do we have'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListPortfoliosInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_portfolio": {
      "post": {
        "operationId": "create_portfolio",
        "summary": "Create a portfolio",
        "description": "Groups clients, or single sites of clients, under a name, to read their traffic, rankings, issues and AI visibility together with get_portfolio_metrics. Answers 'group the dental practices'. Names are unique in the agency. Every member must be a client the caller can reach.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePortfolioInput"
              },
              "example": {
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_portfolio": {
      "post": {
        "operationId": "update_portfolio",
        "summary": "Change a portfolio",
        "description": "Renames or re-describes a portfolio, and adds or removes members — a whole client, or one site with its client. Renaming needs access to every client in it. Adding a member already there is a no-op. Answers 'add this client to the retail portfolio'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePortfolioInput"
              },
              "example": {
                "portfolioId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_portfolio": {
      "post": {
        "operationId": "delete_portfolio",
        "summary": "Delete a portfolio",
        "description": "Deletes a portfolio; its clients and sites are untouched. Needs access to every client in it. Answers 'drop that portfolio'.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeletePortfolioInput"
              },
              "example": {
                "portfolioId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_portfolio_metrics": {
      "post": {
        "operationId": "get_portfolio_metrics",
        "summary": "A portfolio's figures",
        "description": "Traffic, rankings, issues and AI visibility across a portfolio, with each member's own row: Google clicks over the newest 28 days and the 28 before, tracked keywords in the top 3 and 10 and the average position, site health and critical issues from the newest crawl, and how often AI assistants named the brand. Each total says how many members it covers; a member without the data is left out, never counted as zero. A site member is read for that site; AI visibility is per client. Answers 'how are the dental practices doing'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPortfolioMetricsInput"
              },
              "example": {
                "portfolioId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_indexnow_key": {
      "post": {
        "operationId": "get_indexnow_key",
        "summary": "Get the IndexNow key",
        "description": "The client's IndexNow key, the file the site must serve for it, and whether that file has been verified. Lists what submit_indexnow needs in place. A null key means none has been issued yet: use issue_indexnow_key.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetIndexnowKeyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/issue_indexnow_key": {
      "post": {
        "operationId": "issue_indexnow_key",
        "summary": "Issue an IndexNow key",
        "description": "Issues the client's IndexNow key and returns the file to put on the site: fileName at the site's root, containing exactly the key. Answers 'set up IndexNow'. Re-issuing replaces the key and invalidates the file already on the site, so only do it when asked to or when the key must be retired. Hand the file to whoever can publish to the site (sites running the Seolyticize WordPress plugin serve it themselves), then call verify_indexnow_key.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueIndexnowKeyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/verify_indexnow_key": {
      "post": {
        "operationId": "verify_indexnow_key",
        "summary": "Verify the IndexNow key file",
        "description": "Fetches the key file from the client's site and records whether it is there and correct. Answers 'is IndexNow set up'. submit_indexnow submits only for a verified key. A failure says what was found instead (not served, wrong content, unreachable); a site that stops serving the file loses its verification.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyIndexnowKeyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/build_disavow_file": {
      "post": {
        "operationId": "build_disavow_file",
        "summary": "Build a disavow file",
        "description": "Builds a Google disavow file from domains and URLs: a domain entry disavows every link from that domain, a url entry names one page. Answers 'make the disavow file for these links'. Free; nothing is submitted — Google takes the file by upload in Search Console, which a person does. Use get_backlink_audit to find the links worth disavowing, and have a person review every line first: disavowing a good link removes value the client earned. Malformed entries are left out rather than written.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BuildDisavowFileInput"
              },
              "example": {
                "entries": [
                  {
                    "sourceDomain": "example",
                    "scope": "domain"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/queue_url_inspections": {
      "post": {
        "operationId": "queue_url_inspections",
        "summary": "Queue URLs for Search Console inspection",
        "description": "Queues up to 500 of the client's URLs for Search Console's URL inspection, which runs in the background within Google's daily allowance. Answers 'check whether all these pages are indexed'. URLs that are not on the client's own site are refused and listed with the reason. Read the results with get_index_coverage as they arrive; inspect_url checks one URL immediately. Needs Search Console connected (see get_connection_link).",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueueUrlInspectionsInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/notify_google_indexing": {
      "post": {
        "operationId": "notify_google_indexing",
        "summary": "Tell Google a job posting or livestream changed",
        "description": "Sends Google's Indexing API a notification for each address: URL_UPDATED for a new or changed page, URL_DELETED for one taken down. Google accepts it only for pages with JobPosting markup or a BroadcastEvent inside a VideoObject, so each page is checked first — read live for an update, from the latest crawl for a removal — and any other page is refused with the reason (use submit_indexnow or a sitemap for those). At most 200 a day per agency. Needs Search Console connected as the agency's Google account (verify_site) with that account an Owner of the property; a Google sign-in connection cannot send these. dryRun: true checks every page the same way but sends nothing and spends none of the daily allowance, returning wouldSubmit and refused. Answers 'get this job posting indexed now' and 'tell Google the vacancy is filled'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NotifyGoogleIndexingInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_content_audit": {
      "post": {
        "operationId": "get_content_audit",
        "summary": "Content audit: keep, update, merge or review each page",
        "description": "A verdict for every page meant to rank in the latest crawl, from its Google search over the last 90 days against the 90 before (page-level Search Console, top query included), its length and whether it nearly duplicates another page: keep (earning and steady), update (losing clicks, seen but rarely clicked, or thin for the demand it has), merge (near-duplicate of another page) review (no search demand in six months — improve it, fold it into another, or noindex it, after checking its links and conversions; never deleted on this alone) or no_search_data (no Search Console rows for it, and too little history to call that absent demand). Each with the reason; excluded counts the crawled pages left out (non-200, noindex, canonical elsewhere, parameter copies). Without Search Console only merge is judged. Answers 'which pages should we refresh, merge or prune'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetContentAuditInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_nap_consistency": {
      "post": {
        "operationId": "check_nap_consistency",
        "summary": "Do the site and the Google listing agree",
        "description": "Compares the business's name, address and phone on its Google listing with what its site says — the homepage and its contact, about and location pages, text and structured data — and says which agree, which differ and how. Inconsistent details weaken local rankings and confuse assistants. useListing reads the live Google listing (paid, by place id) instead of the location as saved. directories also audits citations: Google is searched for the business's name and phone on Yelp, Foursquare, Facebook, Yellow Pages, Superpages, BBB, Tripadvisor, MapQuest, Apple Maps, Nextdoor and more, plus the trade's own directories (industryDirectories, detected when not given), and each directory's name, address and phone as shown is compared with the listing (null where the result did not show it), with a severity for the worst disagreement — a different name critical, address warning, phone notice; directories with no listing found are named. Bing Places and Apple Business Connect have no self-serve API, so neither is read directly. Answers 'is our NAP consistent' and 'which directories list us wrongly'. Free with the saved location; quote useListing and directories (two results pages) with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckNapConsistencyInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_trust_signals": {
      "post": {
        "operationId": "get_trust_signals",
        "summary": "Who stands behind the site",
        "description": "Checks the signals of who is behind a site that Google's quality raters and AI assistants weigh (E-E-A-T): an about page, a contact page with a way to reach a person, a privacy policy and terms, Organization structured data on the homepage, named authors and publish dates on articles, and HTTPS. Each pass, fail or unknown, with what was found. Answers 'does our site show who we are' and 'what trust signals are missing'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTrustSignalsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_parasite_risk": {
      "post": {
        "operationId": "get_parasite_risk",
        "summary": "Sections that read like rented-out pages",
        "description": "Site reputation abuse risk per section (first path segment) from the crawl's text and links: sponsored or partner phrases per page (1.0 or more is high risk), commerce phrases per page (2.0 or more), outbound links with affiliate parameters such as tag=, aff_id= or ref_= per page (3.0 or more), commerce and affiliate together (high risk), and a section whose commerce rate is more than twice the site's mean (drift — a section that has turned into something else). Each section with its rates, signals, risk and the worst pages. A heuristic, labelled as one. Answers 'is any part of our site at risk under Google's site reputation abuse policy' and 'which section has been turned into coupon or affiliate pages'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetParasiteRiskInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_templated_metadata": {
      "post": {
        "operationId": "check_templated_metadata",
        "summary": "Descriptions a template wrote",
        "description": "Reads every crawled page's title and meta description (latest crawl, or crawlId) for the shapes bulk generation leaves: a description that opens by restating its own title and closes on a stock call to action ('Try it free now.', 'Get started today!'; templated, high), one that only echoes the title (medium), the title's brand suffix pasted into the description (low), and a description that is the title again (medium). Site risk is high when 3 or more pages and at least 30% of those checked are templated, medium from 10%; a stock closer shared by 3 or more pages is flagged too. Returns the counts, the shared closers, and the flagged pages worst first with a fix each. Deterministic string comparison: a heuristic, which claims no Google update targeted the pattern. Answers 'are our meta descriptions templated' and 'which descriptions should we rewrite'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckTemplatedMetadataInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_citation_gap": {
      "post": {
        "operationId": "get_ai_citation_gap",
        "summary": "Why assistants cite others and not this page",
        "description": "For a question assistants answer without citing the client: reads the pages they did cite and the client's page (ourUrl), and says what the cited pages cover that the client's does not — the terms, the sections, the questions they answer — with a 0–100 coverage score and the fixes, as content scoring does against search results. The cited pages come from a tracked question's stored answers (promptId, free), from citedUrls (free), or by asking the ChatGPT app and Perplexity now (question, paid). Answers 'why does ChatGPT cite them and not us' and 'what should this page add to be cited'. Quote a live question with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiCitationGapInput"
              },
              "example": {
                "clientId": "client_123",
                "ourUrl": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_ai_brand_accuracy": {
      "post": {
        "operationId": "check_ai_brand_accuracy",
        "summary": "Do assistants describe the brand correctly",
        "description": "Asks assistants about the client's brand now (the ChatGPT app and Perplexity by default, or chat_gpt, claude, gemini) and checks every claim they make against the facts given — or, by default, the client's registered facts (set_client_facts), and failing those the client brief's overview and positioning — each claim marked supported, contradicted or unverified (the facts do not say), with the fact that decides it. Answers 'what does ChatGPT get wrong about us' and 'is the AI description of our brand accurate'. Paid: the live answers on DataForSEO plus a metered Claude call; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckAiBrandAccuracyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/generate_schema": {
      "post": {
        "operationId": "generate_schema",
        "summary": "Write a page's structured data",
        "description": "Reads one page of the client's site and writes the JSON-LD it should carry: a BreadcrumbList from its path; on the homepage an Organization (with an @id, the social profiles the page itself links to, and the logo from its Open Graph image) and a WebSite; a LocalBusiness from the client's saved location, as the subtype its vertical calls for (from the page's words, or localBusinessType; never the deprecated Attorney), with the address split into a PostalAddress, an @id, branchOf when the client has several locations, openingHoursSpecification from openingHours, areaServed for a service-area business, and never a self-serving aggregateRating; an Article for a post, with dates and author only where the page states them. Nothing is invented — a field the page does not state is left out and named in notes — and types the page already has are listed. Also Product (price, currency, availability and brand from the page's product tags, with OfferShippingDetails and MerchantReturnPolicy from shipping and returns), VideoObject for an embedded YouTube or Vimeo video (Clip per chapter the page lists, else SeekToAction; BroadcastEvent for a live stream), ProfilePage on an author or team page, QAPage on a question page, DiscussionForumPosting on a forum thread, an ItemList of a hub's own pages, SoftwareSourceCode for a page linking its repository, HowTo (its ordered list of steps; Google retired the rich result), Service (for /services/ pages), and on request (type) ProductGroup, FAQPage, SoftwareApplication, Organization, LocalBusiness or Article on any page. Every block is checked against Google's required and recommended properties for its type (validation), so it is clear whether it can earn a rich result as written. FAQPage is written only when asked for: Google stopped showing FAQ rich results for every site on 7 May 2026, and any benefit with assistants is unconfirmed; FAQPage and HowTo blocks carry richResultEligible: false with the reason. Answers 'what schema should this page have', 'write product schema for this page' and 'mark up our locations'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateSchemaInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/generate_llms_txt": {
      "post": {
        "operationId": "generate_llms_txt",
        "summary": "Write the site's llms.txt",
        "description": "Builds an llms.txt for the client's site (the llmstxt.org format: a title, a one-line summary, then sections of links with a description each) from its latest complete crawl — the pages meant to rank, strongest by internal PageRank, grouped by section, each with its own title and description. Says whether the site already publishes one and whether it differs. Nothing is published: put the markdown at publishAt. Answers 'make us an llms.txt'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateLlmsTxtInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_geo_readiness": {
      "post": {
        "operationId": "get_geo_readiness",
        "summary": "How ready the pages are to be cited in AI answers",
        "description": "A 0–100 generative-engine readiness score per page, for the pages given or the top pages by Search Console clicks (up to 20): citability 25 (an answer in the first 40–60 words of each H2 section, self-contained 130–170-word passages, 'X is…' definitions, figures with a cited source, the most citable block in the first 30% of the page), structure 20 (heading hierarchy, question headings, 2–4-sentence paragraphs, tables and lists), multimodal 15 (images, video, VideoObject markup, infographics and charts, calculators and other interactive elements), authority 20 (author, dates, recency — under 3 months best, over 6 stale — links to primary sources, and the brand on Wikipedia, Wikidata, Reddit, YouTube and LinkedIn from the site's sameAs and Wikidata, expert quotes with attribution), technical 20 (server-side rendering from the crawl, OAI-SearchBot, Claude-SearchBot and PerplexityBot allowed, an RSL licence, snippets allowed — nosnippet or max-snippet:0 keeps a page out of AI Overviews and AI Mode, data-nosnippet reported; llms.txt reported at weight 0). Training, search and user crawlers are reported apart, Bytespider, cohere-ai, Google-CloudVertexBot and Google-Agent (which ignores robots.txt) among them. Also a readiness score per answer engine (Google AI Overviews, AI Mode, ChatGPT, Perplexity, Claude, Bing Copilot) from the parts each leans on, 0 where its crawler is blocked: readiness, not measured citations. brandMentions: true adds how often Google finds the brand named on the web, Reddit, YouTube, LinkedIn and Wikipedia (five paid results pages; quote with estimate_cost). Unmeasured parts are null and the rest rescaled; a heuristic, and said so. Answers 'are our pages written to be cited by ChatGPT and Perplexity' and 'what is our GEO score'. Free without brandMentions.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGeoReadinessInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_brand_entity": {
      "post": {
        "operationId": "check_brand_entity",
        "summary": "Does Google know the brand as an entity",
        "description": "Looks the client's brand (default its name) up in Google's Knowledge Graph Search API: whether there is an entity for it, its types, description, Wikipedia article and official URL, whether that URL is the client's own site, and how far it scores ahead of the next candidate — matched, ambiguous or absent — with what to do about each (Organization schema with sameAs, a Wikidata item, one consistent name). Answers 'does Google have a knowledge panel entity for us' and 'is our brand an entity'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckBrandEntityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_agent_readiness": {
      "post": {
        "operationId": "get_agent_readiness",
        "summary": "Get agent readiness",
        "description": "Whether the client's site can be read, cited and used by AI assistants and browsing agents. The original findings (crawler access, rendering, structured data, speed) plus prioritised checks: P0 a made-up path returns a real 404, CLS ≤ 0.1 (Chrome UX Report), robots.txt answers (a 5xx fails), and the homepage's primary content is there without JavaScript (under 50 words in an app shell fails, under 150 warns); P1 a Content-Signal line in every robots.txt group with valid syntax (search, ai-input, ai-train, each yes or no), llms.txt as Lighthouse checks it (an H1, a Markdown link, 50+ characters; a catch-all HTML page fails; /llms-full.txt reported), Markdown delivery (a .md twin, or Accept: text/markdown answered with Vary: Accept), no /.well-known path answering 200 with HTML, and no WebMCP tool telling the agent to skip the user's confirmation; P2 /.well-known/api-catalog and OAuth metadata where the site runs APIs, WebMCP tools registered with document.modelContext (navigator.modelContext alone warns), and an accessibility-tree heuristic (0–100: accessible names, valid roles, nothing focusable hidden) from the rendered homepage; P3 ai-catalog.json found in Lighthouse's order (robots.txt Agentmap, <link rel=ai-catalog>, Link header, /.well-known/ai-catalog.json) and validated against the ARD 1.0 rules (P1 when a signalled catalog fails or errors), agent-card.json, /.well-known/ucp for stores validated against the UCP shape, and declarative WebMCP form attributes. Each check is pass, fail, warn, unmeasured or not applicable; no fix below P0 is recommended while a measured P0 fails. Answers 'why are assistants not citing us' and 'is our site ready for AI agents'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAgentReadinessInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_agent_files": {
      "post": {
        "operationId": "draft_agent_files",
        "summary": "Draft the site's files for AI agents",
        "description": "Drafts, for the client's site, the files AI agents read — nothing is published: robots.txt with a Content-Signal line (search, ai-input, ai-train) in every user-agent group, every Allow and Disallow kept exactly as it is, with aiTrain the user's own choice; an ai-catalog.json in the Agentic Resource Discovery 1.0 shape (specVersion 1.0, standard media types and placeholder representativeQueries) listing the agent card the site already has, with resources ARD has no type for (llms.txt, sitemaps, API catalogs) named in skipped; and WebMCP tool stubs (document.modelContext, falling back to navigator.modelContext) carrying readOnlyHint, consequentialHint and untrustedContentHint, one per real form found on the homepage and the pages given or its contact, booking and sign-up pages, with forms that send, buy or delete marked consequential. Answers 'write our Content-Signal lines', 'make us an ai-catalog.json' and 'how do we expose our forms to browser agents'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftAgentFilesInput"
              },
              "example": {
                "clientId": "client_123",
                "aiTrain": "yes"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_url_safety": {
      "post": {
        "operationId": "check_url_safety",
        "summary": "Is the site, or a site it links to, flagged as unsafe",
        "description": "Looks up the client's homepage, the addresses given, and (outbound, on by default) the external sites its homepage links to on Google's Web Risk lists — malware, social engineering (phishing) and unwanted software — and says which are flagged, with the threat types and until when the match holds. A flagged own page is what turns into a browser warning and lost traffic; a flagged outbound link is a hacked partner or a planted spam link. Answers 'has our site been flagged by Google as unsafe' and 'do we link to any malware sites'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckUrlSafetyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_review_replies": {
      "post": {
        "operationId": "draft_review_replies",
        "summary": "Draft replies to a location's reviews",
        "description": "Drafts owner replies to a location's Google reviews that have no reply yet (newest first, up to limit): thanks that name what the reviewer praised, and for a poor review an apology, what will change and an offline route — never arguing, never inventing facts, no keyword stuffing. voice sets the tone in a sentence. trade (detected from the business by default) holds a healthcare practice's replies to patient privacy (HIPAA: never confirm the reviewer is a patient, never mention care) and a legal practice's to client confidentiality, and each draft that still slips carries a caution. Nothing is posted: read them, then post_review_reply. canPost says whether the listing is connected so they can be posted from here. Answers 'reply to our reviews'. A metered Claude call on the client's budget; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftReviewRepliesInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_outreach_emails": {
      "post": {
        "operationId": "draft_outreach_emails",
        "summary": "Draft outreach emails to link prospects",
        "description": "Drafts one short, personal pitch per prospect on the client's outreach list (up to 20): it names why this site was chosen — the dead page it links to, the thread, the article, the rivals it links to (from the prospect's reason and page) — and what is offered in its place (offer, and ourUrl when given), in the client's voice from its brief. Plain text with a subject; no templates stuffed with merge fields, no false flattery, nothing claimed that the prospect data does not show. Nothing is sent: copy them into your mail tool, then move the prospect to contacted with set_link_prospect_status. Answers 'write the outreach for these sites'. A metered Claude call on the client's budget; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftOutreachEmailsInput"
              },
              "example": {
                "clientId": "client_123",
                "prospectIds": [
                  "example"
                ],
                "offer": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/post_review_reply": {
      "post": {
        "operationId": "post_review_reply",
        "summary": "Post a reply to a Google review",
        "description": "Posts the owner's reply to one Google review — or replaces the reply already there — through the client's connected Business Profile, and records it as answered. Needs the listing connected under Local (the connection asks Google for permission to manage it); reviewId is from draft_review_replies or get_local_visibility. Answers 'post that reply'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostReviewReplyInput"
              },
              "example": {
                "clientId": "client_123",
                "locationId": "example",
                "reviewId": "example",
                "reply": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_domain_keyword_gap": {
      "post": {
        "operationId": "get_domain_keyword_gap",
        "summary": "Keyword gap against competitors",
        "description": "The keywords up to five competitors rank for in Google and the client does not (mode missing), that both rank for (shared), or where the client ranks below them (weak) — merged across the competitors, with volume, difficulty, CPC, intent, the client's position and each competitor's. Works for any domains, tracked or not, from DataForSEO's index; get_keyword_gap is the free reading from what the client's trackers already captured. Answers 'what do our competitors rank for that we don't' and 'where are we losing to them'. One read per competitor. A paid lookup on the client's account unless anyone read the same thing this week (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDomainKeywordGapInput"
              },
              "example": {
                "clientId": "client_123",
                "competitors": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_link_gap": {
      "post": {
        "operationId": "get_link_gap",
        "summary": "Link gap against competitors",
        "description": "The sites that link to competitors but not to the client — match any: at least one competitor (one read each); match all: every competitor (one read) — with each site's rank and how many links it sends each competitor. The outreach list Ahrefs calls Link Intersect, for any domains. Answers 'who links to them and not to us'. source index answers free from our own link index (page-level links and Common Crawl's domain graph; rank is null there); auto uses it when it holds every domain involved (50+ links each, or a complete graph pass) and otherwise asks DataForSEO; vendor always asks DataForSEO. source says which answered. Vendor reads: A paid lookup on the client's account unless anyone read the same thing this week (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLinkGapInput"
              },
              "example": {
                "clientId": "client_123",
                "competitors": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_batch_analysis": {
      "post": {
        "operationId": "get_batch_analysis",
        "summary": "Compare many domains at once",
        "description": "For up to 200 domains (or pages) at once: DataForSEO rank, backlinks, referring domains, organic traffic and organic keywords, in one table. For stored figures without a purchase, batch_domain_metrics. Answers 'size these sites up side by side' and 'which of these prospects are worth it'. Four bulk reads, whatever the number of targets. A paid lookup on the client's account unless anyone read the same thing this week (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBatchAnalysisInput"
              },
              "example": {
                "clientId": "client_123",
                "targets": [
                  "example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_google_trends": {
      "post": {
        "operationId": "get_google_trends",
        "summary": "Google Trends for up to five keywords",
        "description": "Google Trends interest over time (0–100, relative to the busiest point) for up to five keywords compared, by region, and — for a single keyword — the related searches, top and rising. Web search by default, or news, YouTube, images or shopping. Supersedes get_keyword_trends, which reads the United States only. Answers 'is this topic growing', 'when does it peak' and 'which of these terms is bigger'. A paid lookup on the client's account unless anyone read the same thing this week (spend says which); quote it with estimate_cost. (about $0.01)",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGoogleTrendsInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/find_unlinked_mentions": {
      "post": {
        "operationId": "find_unlinked_mentions",
        "summary": "Pages that name the brand but don't link to it",
        "description": "Finds pages that mention the client's brand (brand, or the brand terms from its brief) from DataForSEO's content index, one per site, then reads each (up to limit) and keeps those with no link to the client's site — the easiest links to win, since the writer already chose to talk about it. Each with its domain rank, date and the sentence that names the brand. Answers 'who mentions us without linking'. A paid DataForSEO read plus free page reads; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindUnlinkedMentionsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_page_backlinks": {
      "post": {
        "operationId": "get_page_backlinks",
        "summary": "Who links to one page",
        "description": "The sites linking to one exact page — one row per linking domain, live links only, best domains first — with the linking page, its title, the anchor, dofollow and the domain's rank. Run it on a competitor's dead page from get_competitor_broken_pages to get the people to write to (broken-link building), or on any page to see who cites it. Answers 'who links to that dead page' and 'who would link to ours instead'. A paid DataForSEO read unless anyone read the same page this week; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPageBacklinksInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_competitor_broken_pages": {
      "post": {
        "operationId": "get_competitor_broken_pages",
        "summary": "A competitor's dead pages that still have links",
        "description": "A domain's pages that answer 404 or 410 but that other sites still link to, with how many referring domains (and how many of them dofollow) each still has — the broken-link-building targets: offer the linking sites your page instead. Run on the client's own domain it lists links to reclaim with a redirect (get_broken_backlinks adds the redirect target). source vendor reads DataForSEO's index; index reads our own crawl, free but only pages we have fetched; auto asks the vendor and falls back to the index. Answers 'which of their dead pages could we take the links of'. source vendor (and auto, when a provider is connected) is a paid lookup on the client's account unless anyone read it this week; quote it with estimate_cost. index is free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCompetitorBrokenPagesInput"
              },
              "example": {
                "clientId": "client_123",
                "domain": "example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_outbound_domains": {
      "post": {
        "operationId": "get_outbound_domains",
        "summary": "Domains a site links out to",
        "description": "The domains a site (the client's or any other) links out to, with how many links, how many of them dofollow and the dofollow share, and from how many of its pages. A site that already links to your competitors is an outreach prospect; one linking to dead or spammy domains is a risk. Read from our own crawl of the site; when we have not crawled it, its homepage and up to 15 pages it links to are fetched now. Free. Answers 'who does this site link to' and 'which resources does this niche cite'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetOutboundDomainsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_forum_opportunities": {
      "post": {
        "operationId": "get_forum_opportunities",
        "summary": "Reddit, Quora and forum threads ranking for our keywords",
        "description": "Threads on Reddit, Quora and forums that rank in Google for the client's keywords, with the thread title, address and position, and whether Google shows it in its Discussions and forums box — where a helpful answer earns visibility and referral traffic the client's own page cannot. Answers 'which Reddit threads rank for our keywords' and 'where should we join the conversation'. With no keywords given, reads the tracked keywords' latest captured results pages, free. With keywords (up to 20), reads Google's results for each now: A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetForumOpportunitiesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/search_web_content": {
      "post": {
        "operationId": "search_web_content",
        "summary": "Pages on the web that mention a phrase",
        "description": "Content Explorer over DataForSEO's content index: pages that mention a word or phrase, each with its domain, title, snippet, publish date, domain rank (0–1000), sentiment (positive, negative, neutral) and page type, filtered by page type, sentiment, date and domain rank, and a summary of the whole set — sentiment split, top domains, page types. Answers 'who writes about this', 'who mentions our brand without linking', 'what is said about this topic, and how warmly' and 'which blogs cover this niche'. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SearchWebContentInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/find_link_opportunities": {
      "post": {
        "operationId": "find_link_opportunities",
        "summary": "Resource pages, best-of lists, roundups, podcasts and newsletters for a topic",
        "description": "Finds places that link out by design, from Google results for the search footprints link builders use: resource pages (\"useful links\", intitle:resources), \"best X\" lists, link roundups, podcasts inviting guests, and newsletters taking sponsors or guest pieces — each with the query that found it, its title, snippet and position. The client's own domain and the giant platforms are left out. addToList puts every page on the client's outreach list (as add_link_prospects would; needs client:manage). Answers 'which resource pages could list us', 'which podcasts take guests in our niche' and 'where can we sponsor a newsletter'. One results page per query: queriesPerKind × kinds reads. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindLinkOpportunitiesInput"
              },
              "example": {
                "clientId": "client_123",
                "topic": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/find_journalist_requests": {
      "post": {
        "operationId": "find_journalist_requests",
        "summary": "Journalist requests for sources, from feeds",
        "description": "Reads RSS or Atom feeds of journalist requests for sources and keeps those matching the keywords (all of them when none are given), newest first, with the deadline where the request states one. With no feeds given it reads the public #journorequest, #journorequests and #prrequest feeds on Mastodon (mastodon.social and journa.host) and says so in defaultFeeds, so keywords alone work. Source of Sources sends its queries by email only, Qwoted's and Featured's requests need an account, and SourceBottle publishes no feed — for those, give an email-to-RSS address subscribed to one, or any niche request board's feed. addToList puts each request with a site of its own on the outreach list (needs client:manage); social posts have none. Answers 'which journalists want a source on our topic this week'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindJournalistRequestsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_article": {
      "post": {
        "operationId": "draft_article",
        "summary": "Draft an article from the brief",
        "description": "Writes a full article draft for a keyword, grounded in the content brief built from the pages that rank: the intent and format that win, the target length, the outline, the must-cover terms and the questions to answer, in the client's voice from its brief. Returns Markdown with H2/H3 headings, a meta title and description with pixel-length checks, and which must-cover terms the draft uses and misses (checked by us, not claimed). When the keyword registry already gives the keyword to another page, ownership warns 'this already belongs to /x' (targetUrl: the owner, to draft its rewrite instead). Answers 'write me a first draft for this keyword'. A paid Claude call on the client's budget, plus the brief's results page (free when anyone bought it in the last day). Run score_content on the result before publishing.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftArticleInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/rewrite_section": {
      "post": {
        "operationId": "rewrite_section",
        "summary": "Rewrite a section to cover what is missing",
        "description": "Rewrites (mode rewrite) or extends (mode extend) one section of a page so it covers the terms, entities and questions the content score finds missing, keeping the section's own voice and the client's. Give missingTerms and questions yourself, or the whole draft (draft as Markdown, or url) to have them taken from a fresh score_content run. Returns the new Markdown and which asked-for terms it now uses and still misses, as we count them. Answers 'work these terms into this section'. A paid Claude call; scoring a draft also costs what score_content does.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RewriteSectionInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup",
                "section": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/suggest_meta_tags": {
      "post": {
        "operationId": "suggest_meta_tags",
        "summary": "Titles and descriptions for a whole crawl",
        "description": "Finds the crawled pages whose title or meta description is missing, duplicated, too long or too short (measured in pixels as Google draws them: a 600px title, a 920px description — not characters), and writes a new title and description for each, keeping the Search Console queries the page already earns clicks for. Every suggestion is pixel-checked again. Returns rows, and with format csv a spreadsheet of url, problems, current and suggested values and their widths. Answers 'fix the titles across the site'. Reads the latest complete crawl unless crawlId is given; urls narrows it. A paid Claude call per 25 pages.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuggestMetaTagsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/forecast_keyword_traffic": {
      "post": {
        "operationId": "forecast_keyword_traffic",
        "summary": "What a keyword set is worth at target positions",
        "description": "Estimated organic clicks for a set of keywords at the positions aimed for (default 1, 3, 5 and 10): volume × the click curve for the market (measured by the panel where it can be, published otherwise, and said which), shaped month by month by each keyword's seasonality from stored monthly volumes, with a time-to-rank estimate from difficulty and the client's current position, and first-year clicks counting only from the month the page is likely to arrive. Totals for the set. keywords are strings, or { term, searchVolume, difficulty } when the figures are known. Answers 'what is this cluster worth if we rank'. Free: volumes and difficulty are read from what is stored, or given; a keyword never looked up is reported with unknown volume rather than zero.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForecastKeywordTrafficInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  {
                    "term": "carrier lookup"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/research_topic": {
      "post": {
        "operationId": "research_topic",
        "summary": "Subtopics, questions and headlines around a seed",
        "description": "Maps a topic: related keywords and keyword suggestions for a seed, with volume, difficulty and search intent, grouped into subtopics by the word they add to the seed; the questions people ask (People Also Ask and question keywords); and the headlines ranking now. Answers 'what should we write about around this topic'. Paid DataForSEO Labs reads and one results page on the client's account, each free when anyone read it lately.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResearchTopicInput"
              },
              "example": {
                "clientId": "client_123",
                "seed": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_personal_keyword_difficulty": {
      "post": {
        "operationId": "get_personal_keyword_difficulty",
        "summary": "How hard a keyword is for this site",
        "description": "Keyword difficulty adjusted for the client's own site: its authority against the first page's, how much of the topic it already ranks for, and whether it already ranks for the keyword — each adjustment returned with its reason, so the number can be argued with. Answers 'which of these can we actually win'. Free: read from stored first pages, link counts, authority and rankings; a factor with no data behind it is left out and said so.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPersonalKeywordDifficultyInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_report_link": {
      "post": {
        "operationId": "create_report_link",
        "summary": "Make a shareable report page",
        "description": "A signed, expiring, read-only link to one of a client's saved reports (from list_reports) as a web page under the agency's own branding, plus downloadUrl for the same report as a self-contained HTML file. Answers 'send the client a link to the report' or 'give me the report as HTML'. Covers the last periodDays days (default 30) as of now, fixed: the page does not change as time passes. Anyone holding the link can read it until it expires (expiresInDays, default 14, at most 90), so only make one when the user asks. The url is shown only in this answer and is never stored; linkId names it for list_report_links and revoke_report_link. revoke_report_links turns every earlier link off. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportLinkInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_report_links": {
      "post": {
        "operationId": "revoke_report_links",
        "summary": "Turn off a report's links",
        "description": "Stops every link made so far with create_report_link for one saved report, at once. Answers 'turn off all the links to this report'. To stop one link and keep the rest, revoke_report_link. Links made afterwards work as normal. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeReportLinksInput"
              },
              "example": {
                "clientId": "client_123",
                "reportId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_report_links": {
      "post": {
        "operationId": "list_report_links",
        "summary": "List live report links",
        "description": "The share links made with create_report_link that still open, newest first, for one client or (without clientId) every client the caller can see: each with linkId, the report, its period, when it was made and by whom, when it expires, and when it was last opened (lastViewedAt, null if never) with a view count. Answers 'which report links are out there' and 'has the client opened the report'. The address itself is not returned: it is a secret shown once and never stored, so make a new link to send it again. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListReportLinksInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_report_link": {
      "post": {
        "operationId": "revoke_report_link",
        "summary": "Turn off one report link",
        "description": "Stops one link made with create_report_link (linkId from list_report_links or from create_report_link's answer) at once, leaving the report's other links working. Answers 'I sent the report link to the wrong person'. Revoking a link twice keeps the first time. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeReportLinkInput"
              },
              "example": {
                "linkId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_report_data": {
      "post": {
        "operationId": "get_report_data",
        "summary": "Every figure a monthly report needs",
        "description": "One read of a client's period, from..to inclusive, against the period before (compareTo previous_period, the default) or the same days a year earlier (previous_year): searchConsole (clicks, impressions, CTR and position in total, branded and non-branded, with the non-branded queries and pages that moved most), analytics (GA4 organic sessions, key events and revenue, or the first-party web analytics' visits), revenue (imported orders by currency, organic and AI channels, attribution coverage — as get_seo_revenue), rankings (each tracker's summary and movers between the period's ends), audit (the latest crawl in the period, its health, and new and fixed issues against the last crawl before it), backlinks (gained and lost), aiVisibility (mention rate against the comparison), annotations (the timeline, with Google's updates) and alerts fired. A section is null with unavailableReason when the client lacks that source. Answers 'pull October's numbers for the report'. Use it first; the single tools go deeper on one section. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetReportDataInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_budget_status": {
      "post": {
        "operationId": "get_budget_status",
        "summary": "A client's budget and month-end forecast",
        "description": "A client's monthly budget (null when none is set), what it has spent this month, what is left, when the month resets and the alert share, plus projection: an estimate of month-end spend from the paid work already scheduled — each rank tracker's cadence × keywords × devices × price, AI visibility checks on their cadence, and alert rules with their paid source on — priced from the same ceilings estimate_cost quotes, so the real figure is usually lower. Answers 'how much budget is left' and 'will this client go over this month' before any paid call. set_budget changes the budget; get_client_costs says what the spend went on. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "cost:view",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBudgetStatusInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_scheduled_work": {
      "post": {
        "operationId": "get_scheduled_work",
        "summary": "Every scheduled paid job, with how to pause it",
        "description": "Lists each piece of paid work that runs on a schedule for a client — the weekly domain sweep, rank trackers, AI visibility checks, alert rules with a paid source — with what a month of it costs, who turned it on where that is recorded, and the exact call that pauses it and the one that resumes it. The same items as get_budget_status.projection, plus any that could not be priced. Answers 'what is this client paying for on a schedule, and how do I stop it'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "cost:view",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetScheduledWorkInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_lead_widget": {
      "post": {
        "operationId": "create_lead_widget",
        "summary": "Create a lead-gen audit widget",
        "description": "Makes an audit form for the agency's own website: a visitor enters their URL and email, sees a short audit of the page on the spot, and lands in list_leads. Returns embedCode to paste into the site and frameUrl for the form alone. Answers 'put a free audit form on our site'. Limited per visitor and guarded against internal addresses. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLeadWidgetInput"
              },
              "example": {
                "name": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_lead_widgets": {
      "post": {
        "operationId": "list_lead_widgets",
        "summary": "List lead-gen widgets",
        "description": "The agency's audit forms, each with its embed code, allowed sites, who is notified and whether it is switched on. Answers 'which audit forms do we have on our sites'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListLeadWidgetsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_lead_widget": {
      "post": {
        "operationId": "update_lead_widget",
        "summary": "Change a lead-gen widget",
        "description": "Renames a widget, changes its heading, colour, allowed sites or who is notified, or switches it off and on (enabled). A switched-off form stops taking requests at once; its leads are kept. Answers 'turn off the form on our old site'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLeadWidgetInput"
              },
              "example": {
                "widgetId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_leads": {
      "post": {
        "operationId": "list_leads",
        "summary": "List leads from audit widgets",
        "description": "People who asked for an audit through the agency's widgets, newest first: email, the page they checked, where the form was, the audit they were shown (counts, page title and findings), and whether the agency was emailed (notifyError says why not). Answers 'who filled in our audit form'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "agency:settings",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListLeadsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_bing_search_stats": {
      "post": {
        "operationId": "get_bing_search_stats",
        "summary": "Bing queries or pages, week by week",
        "description": "Bing Webmaster Tools' query stats or page stats for the client's site, each row with its clicks, impressions and position and its weekly history (Bing publishes weekly, about six months back). Give query to see which pages answered that one query, or page to see which queries that one page answered. Answers 'what do people find us for on Bing' and 'which page does Bing show for this'. Bing's numbers about Bing's searchers, on the agency's Webmaster Tools key; never add them to Google's. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBingSearchStatsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_bing_crawl_health": {
      "post": {
        "operationId": "get_bing_crawl_health",
        "summary": "How Bing crawls the site",
        "description": "Bing's crawl stats by day (pages crawled, in index, errors by HTTP class, blocked by robots.txt, DNS failures and timeouts), the URLs Bing reports crawl issues for with the issues counted by type, and the pages or directories blocked from Bing's results. Answers 'is Bing having trouble crawling us' and 'did someone hide a page from Bing'. Bing's API has no penalty or manual-action feed, so none is reported. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBingCrawlHealthInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_bing_inbound_links": {
      "post": {
        "operationId": "get_bing_inbound_links",
        "summary": "Links Bing knows point at the site",
        "description": "Bing's own link data from Webmaster Tools: without url, the client's pages that have inbound links and how many each has; with url (a page on the client's site), the pages linking to it and their anchor text. Paged as Bing pages it (page from 0; totalPages says how many). Answers 'which of our pages earn links, according to Bing' and 'who links to this page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBingInboundLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_bing_keyword_research": {
      "post": {
        "operationId": "get_bing_keyword_research",
        "summary": "Bing's own search volume for a term",
        "description": "Bing Webmaster Tools' keyword research on the agency's key: the term's Bing impressions week by week (exact and broad match) and related terms with their impressions over a date range. Bing publishes real counts rather than bands. Answers 'how often is this searched on Bing' and 'what else do Bing users search around it'. country is a two-letter code, language a tag such as en-GB. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetBingKeywordResearchInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_bing_site": {
      "post": {
        "operationId": "add_bing_site",
        "summary": "Add the site to Bing Webmaster Tools",
        "description": "Adds the client's site to the agency's Bing Webmaster Tools account (the one the saved key belongs to), if it is not there yet, and returns Bing's three proofs: file (/BingSiteAuth.xml, served exactly as given), meta (the msvalidate.01 tag) and dns (a CNAME to verify.bing.com). Answers 'add this site to Bing' and 'how do we verify the site in Bing'. Deploy one proof, then call verify_bing_site. Safe to repeat: an added site is returned as it is. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddBingSiteInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/verify_bing_site": {
      "post": {
        "operationId": "verify_bing_site",
        "summary": "Verify the site in Bing Webmaster Tools",
        "description": "Asks Bing to check the proof add_bing_site gave (the BingSiteAuth.xml file, the msvalidate.01 meta tag or the CNAME), and answers verified. Once it is, get_bing_search_stats, get_bing_crawl_health and the other Bing tools read the site. Answers 'is the site verified in Bing'. A site already verified is answered at once. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyBingSiteInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_bing_urls": {
      "post": {
        "operationId": "submit_bing_urls",
        "summary": "Submit pages to Bing",
        "description": "Submits addresses on the client's site to Bing through Webmaster Tools' URL submission (SubmitUrlBatch), after reading the site's daily quota: addresses beyond what is left today are returned as not sent rather than refused by Bing one by one. Answers 'get Bing to index these pages now'. Only addresses on the client's own site are sent. submit_indexnow reaches Bing too, without the quota, once the client's IndexNow key is published. dryRun: true reads the quota but sends nothing, returning wouldSubmit, refused, and the quote.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitBingUrlsInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/inspect_bing_url": {
      "post": {
        "operationId": "inspect_bing_url",
        "summary": "Ask Bing what it holds for one page",
        "description": "Bing's index details for one address on the client's site (GetUrlInfo): when Bing discovered and last crawled it, the HTTP status and size it got, links pointing at it and, for a directory, how many pages sit under it — plus its Bing clicks and impressions. Answers 'is this page in Bing, and when did Bing last see it'. Free; no daily allowance.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InspectBingUrlInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/submit_bing_sitemap": {
      "post": {
        "operationId": "submit_bing_sitemap",
        "summary": "Submit a sitemap to Bing",
        "description": "Submits a sitemap or feed (XML sitemap, RSS 2.0, Atom or a text list) on the client's site to Bing Webmaster Tools. Answers 'tell Bing about this sitemap'. list_sitemaps then shows it with Bing's reading. Refuses addresses not on the client's site.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitBingSitemapInput"
              },
              "example": {
                "clientId": "client_123",
                "sitemapUrl": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/verify_yandex_host": {
      "post": {
        "operationId": "verify_yandex_host",
        "summary": "Add and verify the site in Yandex Webmaster",
        "description": "Adds the client's site to the connected Yandex Webmaster account if it is not there, asks Yandex to check the chosen proof (method file: /yandex_<code>.html; meta: the yandex-verification tag; dns: a TXT record), and once verified points the connection at it so get_yandex_performance, get_yandex_indexing and the other Yandex tools read the site. Answers 'add this site to Yandex' and 'is the site verified in Yandex'. Returns the proof to deploy while unverified; Yandex checks in the background, so call again after IN_PROGRESS. Needs a Yandex token with webmaster:verify as well as webmaster:hostinfo. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyYandexHostInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_indexing": {
      "post": {
        "operationId": "get_yandex_indexing",
        "summary": "Which pages Yandex has in search",
        "description": "Yandex Webmaster's indexing views for the client's verified host: pages in search by day and a sample of them, pages that appeared in or were removed from search by day and a sample with Yandex's reason for each removal (duplicate, not canonical, noindex, HTTP error, low quality...) counted by reason, and a sample of what the robot fetched with the status it got. Answers 'which pages has Yandex dropped, and why'. Samples are paged (limit up to 100). Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexIndexingInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_external_links": {
      "post": {
        "operationId": "get_yandex_external_links",
        "summary": "Links Yandex knows point at the site",
        "description": "Yandex's count of external links to the client's host over time, and a page of the links themselves (source page, the page of ours it points to, when Yandex found it). Answers 'is our link count growing in Yandex' and 'who links to us, per Yandex'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexExternalLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_diagnostics": {
      "post": {
        "operationId": "get_yandex_diagnostics",
        "summary": "What Yandex says is wrong with the site",
        "description": "Yandex Webmaster's site diagnostics: each check (robots.txt blocking the site, DNS or SSL errors, a slow server, missing or broken sitemaps, duplicate pages, missing titles, not mobile friendly...) with its severity and whether the problem is present now, worst first. Answers 'does Yandex see anything broken'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexDiagnosticsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_important_pages": {
      "post": {
        "operationId": "get_yandex_important_pages",
        "summary": "The pages Yandex is watching for the site",
        "description": "Yandex Webmaster's important-pages monitoring: each page the site owner chose to watch, with its last crawl status and HTTP code, whether it is searchable, its title and description in Yandex, why it is excluded if it is, and what changed since the previous check. Answers 'are our key pages still in Yandex'. Pages are chosen in Yandex Webmaster itself; the API only reads them. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexImportantPagesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_yandex_query_history": {
      "post": {
        "operationId": "get_yandex_query_history",
        "summary": "Yandex search traffic by day",
        "description": "Yandex Webmaster's search query history: shows, clicks and average show and click position by day for the whole site, or for one query (queryId, from get_yandex_performance's queries), optionally for one device. Answers 'how has our Yandex traffic moved' and 'how is this query trending in Yandex'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYandexQueryHistoryInput"
              },
              "example": {
                "clientId": "client_123",
                "from": "2026-10-01",
                "to": "2026-10-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_naver_keyword_volumes": {
      "post": {
        "operationId": "get_naver_keyword_volumes",
        "summary": "Naver's own search volume",
        "description": "Monthly searches on Naver, PC and mobile, from the keyword tool in the agency's Naver Search Ad account, for up to 50 terms, with Naver's related terms when includeRelated is true. The only source of Naver demand: no vendor resells it. Terms too rare are reported by Naver as under ten and flagged so, not given a number. Answers 'how often is this searched on Naver'. Free; needs the agency's Naver Search Ad credentials.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetNaverKeywordVolumesInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_engine_capabilities": {
      "post": {
        "operationId": "get_engine_capabilities",
        "summary": "What can be done on each search engine",
        "description": "The matrix of what this product does on each engine — Google, Bing, YouTube, Amazon, Yandex, Baidu, Naver, DuckDuckGo, Yahoo, Seznam, App Store, Google Play — for rank tracking, live results, search volume, difficulty, keyword ideas, ranked keywords, top pages, content profiles, SERP features and history, webmaster data and URL submission. Each cell is supported (with the tools that do it), not_offered_by_engine (the engine publishes nothing to read) or not_built, with a note. Also lists the AI answer engines and whether their data is sampled by Seolyticize or from DataForSEO. Answers 'can you do X on Bing' and 'why is there no Naver index data'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetEngineCapabilitiesInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_share_of_search": {
      "post": {
        "operationId": "get_share_of_search",
        "summary": "The brand's share of each engine",
        "description": "For the client's tracked keywords (narrowed to a topic, or to given keywords): one number per engine and the brand's share of it — Google, Bing and YouTube (estimated click share from the latest rank captures, beside the total search volume), Google's AI Overviews (share of the citations they showed), AI Mode and the other AI assistants (share of brand mentions in the answers Seolyticize sampled). Read only from stored data, so free; an engine with no trackers, captures or sampled answers is listed under noData with why. Answers 'where are we visible beyond Google' and 'what share of AI answers name us'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetShareOfSearchInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_engine_keyword_ideas": {
      "post": {
        "operationId": "get_engine_keyword_ideas",
        "summary": "Keyword ideas for Bing or Amazon",
        "description": "Keyword ideas around seed terms on another engine: engine bing reads DataForSEO's Bing keywords-for-keywords (with Bing volume, CPC, competition and monthly history; English, French and German), engine amazon reads DataForSEO Labs' Amazon related keywords (with Amazon search volume; one seed). Answers 'what do people search on Amazon around this product' and 'what are the Bing variations of this term'. Google ideas are keyword_explorer. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetEngineKeywordIdeasInput"
              },
              "example": {
                "clientId": "client_123",
                "engine": "bing",
                "seeds": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_app_metrics": {
      "post": {
        "operationId": "get_app_metrics",
        "summary": "How visible apps are in an app store",
        "description": "For up to 1,000 apps in the App Store (numeric ids, from /id… in the store URL) or Google Play (package names): how many search results pages each appears on, how many at #1, #2–3, #4–10 and #11–100, and the total search volume of those keywords, from DataForSEO Labs (US English only). Answers 'how visible is our app against these competitors'. get_ranked_keywords with engine app_store or google_play lists one app's keywords. A paid lookup on the client's account unless anyone read the same thing recently (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAppMetricsInput"
              },
              "example": {
                "clientId": "client_123",
                "engine": "app_store",
                "appIds": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ctr_outliers": {
      "post": {
        "operationId": "get_ctr_outliers",
        "summary": "Queries clicking far from what they should",
        "description": "Fits the site's own click-through rate by position bucket and device — and by results-page shape (AI Overview, featured snippet, map pack, shopping, video, plain) where rank captures say what the page showed — then lists Search Console queries more than sigma (default 2) standard deviations under it (a title or snippet problem: under, with the clicks missed) and over it (a snippet worth copying: over). Falls back to the published industry curve where the site has too few queries in a bucket, and model says which was used (site, published or mixed). Answers 'which snippets should we rewrite' and 'which titles work best'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCtrOutliersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_query_intents": {
      "post": {
        "operationId": "get_query_intents",
        "summary": "Search traffic by intent or topic",
        "description": "Google web clicks, impressions and position grouped by what each Search Console query asks for — informational, commercial, transactional or navigational (navigational: it names the client, from the brief's brand terms) — or by topic (queries sharing their most common words). Every query is tagged after each Search Console sync; query_data can also group or filter by intent, topic and branded. Answers 'how much of our traffic is people ready to buy' and 'which topics bring the clicks'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetQueryIntentsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_search_anomalies": {
      "post": {
        "operationId": "get_search_anomalies",
        "summary": "Unusual days in search traffic, explained",
        "description": "Days when Google clicks fell or jumped well outside their normal range — for the whole site, each section (first path segment) and each query topic — against a robust same-weekday baseline (median and MAD over eight weeks), consecutive days joined into one episode. Each names the likely cause from the timeline with a confidence: a crawl regression (pages gone 404 or newly noindex), a deploy or crawl change, a Google update, a lost SERP feature, or a page swap (the ranking URL changed). Also lists what the daily check already raised. Answers 'why did traffic drop on Tuesday' and 'is anything wrong with search'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSearchAnomaliesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/forecast_search_clicks": {
      "post": {
        "operationId": "forecast_search_clicks",
        "summary": "The next 90 days of non-branded clicks",
        "description": "Forecasts daily non-branded Google clicks for the next 90 days (horizonDays) from the site's own history: level, a damped trend, the weekly rhythm and last year's seasonality (needs 13 months of history; with less, pass trends — Google Trends interest for the site's head term from get_google_trends, past_5_years — to stand in), with an 80% band. scenario adds 'what if we win the striking-distance set': every query at positions 4–15 moved to 3, using the site's own click-through curve, the gain arriving over 60 days. Answers 'how much traffic should we expect next quarter' and 'what is the striking-distance work worth'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForecastSearchClicksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_zero_click_estimates": {
      "post": {
        "operationId": "get_zero_click_estimates",
        "summary": "How many searches end without a click",
        "description": "For each Search Console query that a tracked keyword's latest capture describes, the estimated share of searches that end with no organic click, from the features on its results page (AI Overview, featured snippet, map pack, shopping, knowledge panel, video…) — measured on this site's own click-through curve where it can be, a published share otherwise (source says which) — and how many of the query's searches that is. Answers 'how much demand is the AI Overview eating' and 'which keywords are worth less than their volume says'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetZeroClickEstimatesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_page_indexing_reasons": {
      "post": {
        "operationId": "get_page_indexing_reasons",
        "summary": "Why pages are not indexed",
        "description": "Search Console's Page indexing report, rebuilt (its API has none): every sitemap and crawled page with one reason it is or is not in Google — noindex, blocked by robots.txt, 404, server error, redirect, soft 404, Google chose another canonical, crawled or discovered but not indexed, unknown to Google — from URL Inspection (2,000 a day per property, worked through the sitemap a batch a day) and our crawl, which stands in, marked, for pages not inspected yet. Rolled up per template (path pattern) with the share indexed and the main reason, and a fix for each reason. Filter by template or reason. Answers 'why isn't this page indexed' and 'which templates are kept out of Google'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPageIndexingReasonsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_volume_calibration": {
      "post": {
        "operationId": "get_volume_calibration",
        "summary": "How far vendor volumes are off for this site",
        "description": "The correction factor between the vendor's search volumes and what Search Console counted, per market: for queries where the site held positions 1–3 (where impressions are close to searches), the median of impressions over volume, with how many terms it rests on and their spread. Keyword tools add calibratedVolume next to volume where a factor exists. Answers 'can we trust these search volumes' and 'why does Search Console show more searches than the keyword tool'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetVolumeCalibrationInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_intent_shifts": {
      "post": {
        "operationId": "get_serp_intent_shifts",
        "summary": "Keywords whose results page changed character",
        "description": "Tracked keywords whose results page changed what it is for between its two latest captures: the mix moving (informational, commercial, local, plain — e.g. informational → commercial when shopping results arrive) or a watched feature appearing or going (AI Overview, video carousel, shopping, map pack, featured snippet, top stories). A page that no longer fits the results page's intent loses however good it is. Answers 'did Google change what it shows for our keywords' and 'where did AI Overviews appear'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpIntentShiftsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_questions": {
      "post": {
        "operationId": "get_questions",
        "summary": "The questions people ask, from every source",
        "description": "Questions about the client's subject merged from People Also Ask and related searches on captured results pages, the client's AI visibility prompts, Reddit and Quora threads ranking for tracked keywords, Search Console queries phrased as questions, and the site's own search box (GA4) — phrasings of one question deduplicated — each with its sources, volume where a source measured it (impressions, site searches, or volume, kept apart) and whether a page of the site answers it: answered (a heading asks or states it), mentioned (the text has its words) or unanswered, from the latest crawl. sources says which could be read. Answers 'what should our FAQ cover' and 'which questions have no page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetQuestionsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_serp_newcomers": {
      "post": {
        "operationId": "get_serp_newcomers",
        "summary": "Who is new in the top 20",
        "description": "Domains that entered the top 20 for any of the client's tracked keywords in the last days (default 7) and were in none of their top 20s in the baselineWeeks before, with the pages they rank with, most keywords first. The client's own domain is left out. Answers 'who is new in our search results this week' and 'which competitor just started ranking'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSerpNewcomersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_long_tail_candidates": {
      "post": {
        "operationId": "get_long_tail_candidates",
        "summary": "Queries with impressions and no page of their own",
        "description": "Search Console queries the site is shown for where the page Google picked is about something else — its title and H1 (from the latest crawl) cover under half the query's words — clustered by shared words into write candidates, biggest first, each with its queries, impressions and the pages ranking now (where to link the new page from). Branded queries are left out. Answers 'what should we write next' and 'which searches have no page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLongTailCandidatesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_link_velocity": {
      "post": {
        "operationId": "get_link_velocity",
        "summary": "Referring domains gained and lost per day",
        "description": "New and lost referring domains per day for the client and its tracked competitors (or the domains given), from our own link index and the vendor links already synced, each against the domain's own baseline of the preceding weeks: spikes (a day of new referring domains far above its usual — a campaign, a viral piece, or somebody pointing a link farm at the site) and lost clusters (many domains lost on one day — a network deindexed, a partner's redesign, a broken migration), with example domains, and five red flags with the action each calls for (10× the usual new links in a week, half the links lost in a month, no new links for three months, every new link from one TLD, a spike from one country). Losses are only called after graceDays unseen, and not at all for a domain no index is still reading. Answers 'are we gaining links faster than usual', 'did we just lose a batch of links' and 'is a competitor running a link campaign'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLinkVelocityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_toxic_link_risk": {
      "post": {
        "operationId": "get_toxic_link_risk",
        "summary": "Which linking sites are a risk, and why",
        "description": "Judges each site linking to the client from the evidence a person can check: the vendor's spam score (fetchSpamScores: true buys it for every linking site inside this call — one paid DataForSEO request of up to 1,000 sites, the price of get_backlink_spam_scores, with sites scored in the last 30 days reused free; or pass spamScores you already have), sitewide links (the link on most of the pages we hold of the site: a footer or blogroll), link-seller neighbourhoods (a site linking out to hundreds of domains from few pages), commercial exact-match anchors (pass moneyTerms; brand terms are excluded), the vendor links' own authority and outbound signals, and claude-seo's thirty toxic patterns where the data allows (a page with 10,000+ or 50+ outbound links, a domain registered under 30 days ago with 100+ outbound links or re-registered after it lapsed — from RDAP for the sites linking out most — pharma or casino injections, sitewide links and exact-match anchors from unrelated sites, foreign-language and parked sites, article directories, forum profiles, press release wires, coupon sites, comment links, unrelated niches when moneyTerms say what the client does), each pattern reported flagged, clear or unmeasured with why. disavow says whether a file is worth making (toxic over 10% of the sites: yes; under 2%: no). A verdict (healthy, review, toxic) and every reason with its detail; whether the last saved disavow file already names the site, and the toxic sites that appeared since it. Answers 'which of our links are toxic and why' and 'what should go in the disavow file now'. 'review' means look, not disavow. Free without fetchSpamScores; with it, quote it with estimate_cost or dryRun first.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetToxicLinkRiskInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/save_disavow_file": {
      "post": {
        "operationId": "save_disavow_file",
        "summary": "Build, keep and compare a disavow file",
        "description": "Builds a Google disavow file for the client from domains and URLs (as build_disavow_file does), keeps it in the client's disavow history, and says what changed against the previous saved file: domains and URLs added and dropped. Nothing is submitted — Google takes the file by upload in Search Console, which a person does after reviewing every line. Answers 'make this month's disavow file and show what changed'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveDisavowFileInput"
              },
              "example": {
                "clientId": "client_123",
                "entries": [
                  {
                    "sourceDomain": "example",
                    "scope": "domain"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_disavow_history": {
      "post": {
        "operationId": "get_disavow_history",
        "summary": "The client's saved disavow files",
        "description": "The disavow files saved for the client, newest first, with how many domains and URLs each names, and what the newest changed against the one before. Answers 'what did we disavow last time' and 'what changed in the disavow file'. get_toxic_link_risk lists risky sites that appeared since. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetDisavowHistoryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_referring_networks": {
      "post": {
        "operationId": "get_referring_networks",
        "summary": "Which networks the links come from",
        "description": "The IP addresses or subnets (type ip or subnet) the client's links — or any target's — come from, from DataForSEO's referring networks: per network its backlinks, referring domains and main domains, rank, first seen and lost date, with the networks carrying links from five or more separate domains flagged. Many unrelated sites on one address is the shape of a private blog network; a shared host puts honest sites together too, so a flag means look at the sites, not disavow. Answers 'are our links from a link network' and 'how many of these sites share a server'. One paid DataForSEO request; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetReferringNetworksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_outreach_mailboxes": {
      "post": {
        "operationId": "get_outreach_mailboxes",
        "summary": "Mailboxes outreach is sent from",
        "description": "The Gmail and Microsoft 365 mailboxes connected for the client's outreach, with when replies were last checked and any error, and the links where a person connects another (they sign in themselves; nothing here can). Answers 'which mailbox do we send from' and 'is outreach email working'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetOutreachMailboxesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_outreach_sequence": {
      "post": {
        "operationId": "create_outreach_sequence",
        "summary": "Create an outreach sequence",
        "description": "Saves a sequence for the client: the first email and up to five follow-ups, each sent delayDays after the one before unless the prospect has replied (the first step's delay is ignored: it goes when send_outreach is called). Subjects and bodies may use {{site}} (the prospect's domain), {{page}} (its page, or the domain) and {{client}} (the client's name). Follow-ups go into the same thread. Answers 'set up a three-step outreach sequence'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOutreachSequenceInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example",
                "steps": [
                  {
                    "delayDays": 0,
                    "subject": "example",
                    "body": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_outreach_sequences": {
      "post": {
        "operationId": "list_outreach_sequences",
        "summary": "The client's outreach sequences",
        "description": "The sequences saved for the client, newest first, with their steps. Answers 'which sequences do we have'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListOutreachSequencesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/send_outreach": {
      "post": {
        "operationId": "send_outreach",
        "summary": "Send outreach emails from a connected mailbox",
        "description": "Sends the first email to each prospect from the chosen mailbox now, and schedules the sequence's follow-ups (when a sequenceId is given), which the hourly sweep sends unless a reply arrives first. Each prospect takes its own subject and body (from draft_outreach_emails, say) or the sequence's first step; the address is to, or the contact saved on the prospect. A prospect with no address, or already contacted, is skipped and listed. Sent prospects move to contacted. This sends real email from a person's mailbox: confirm the list and the wording with the user first — dryRun: true sends nothing and returns wouldSend, every email (address, subject, body) and follow-up (with when it would go) exactly as it would be sent. Answers 'send these outreach emails'. No vendor charge.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendOutreachInput"
              },
              "example": {
                "clientId": "client_123",
                "mailboxId": "example",
                "prospects": [
                  {
                    "prospectId": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/sync_outreach": {
      "post": {
        "operationId": "sync_outreach",
        "summary": "Check outreach threads for replies, and send due follow-ups",
        "description": "Does now what the hourly sweep does for this client: reads every live outreach thread for a reply (moving a prospect who answered to replied and calling off its follow-ups), then sends the follow-ups that are due. Answers 'did anyone reply to our outreach'. No vendor charge; it sends due follow-ups, so it needs client:manage.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncOutreachInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_outreach_status": {
      "post": {
        "operationId": "get_outreach_status",
        "summary": "Where each outreach conversation stands",
        "description": "Every prospect the client has written to, with its stage, contact, when it replied, and each email of its sequence: sent, scheduled, failed or called off. Answers 'who have we emailed', 'who replied' and 'what is going out this week'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetOutreachStatusInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/audit_merchant_feed": {
      "post": {
        "operationId": "audit_merchant_feed",
        "summary": "Audit the Merchant Center product feed",
        "description": "Reads the client's connected Google Merchant Center account (Merchant API) and audits its products: Google's own item-level issues grouped by code, worst first (disapproved, then demoted), with how many products each hits, examples and Google's help link; approval counts per destination; and what Google does not flag but Shopping placement rewards — titles too short or without the brand, thin descriptions, missing GTINs, single images, out of stock. Answers 'why are our products disapproved' and 'how good is our feed'. Needs Merchant Center connected (get_connection_link names the link; /api/connect/merchant/start). Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuditMerchantFeedInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/validate_product_schema": {
      "post": {
        "operationId": "validate_product_schema",
        "summary": "Check Product and Offer structured data",
        "description": "Reads product pages and checks their Product and Offer JSON-LD against what Google's merchant listings need — errors: name, image, offers as Offer (not AggregateOffer) with a price above 0 and an ISO 4217 priceCurrency (or a priceSpecification), a valid availability; warnings: brand (its name not empty or N/A), a GTIN or MPN or SKU, description, offers.url, itemCondition, priceValidUntil when it has passed, validFrom without an end date, shipping details with shippingDestination and deliveryTime, a return policy with applicableCountry and returnPolicyCategory, a rating with ratingValue and reviewCount, hasAdultConsideration values, a ProductGroup's productGroupID, variesBy and hasVariant, and with eu: true the energy efficiency class; notes: returnPolicyCountry, member programs, variants — says whether each page is eligible, and gives a completenessScore (required fields 50, aggregateRating 65, an identifier 75, shippingDetails 85, a return policy 90, three or more reviews 100). With no urls, the latest crawl's pages that carry Product markup (up to limit). render 'auto' renders a page in a browser when its HTML carries no Product markup, for stores that inject their JSON-LD with JavaScript. Answers 'is our product schema right' and 'why don't our products show prices in Google'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateProductSchemaInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_shopping_serp": {
      "post": {
        "operationId": "check_shopping_serp",
        "summary": "Queue Google Shopping results for keywords",
        "description": "Queues a Google Shopping results page for each keyword (up to 20) at DataForSEO, which answers in a few minutes; collect them with get_shopping_serp and the task ids returned. Answers 'track our Google Shopping positions'. One purchase per keyword. A paid lookup on the client's account (spend says how much); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckShoppingSerpInput"
              },
              "example": {
                "clientId": "client_123",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_shopping_serp": {
      "post": {
        "operationId": "get_shopping_serp",
        "summary": "Google Shopping positions, now and over time",
        "description": "Collects the Shopping pages queued by check_shopping_serp, keeps them, and says where the client's products sit — matched on the seller names given (default the client's name) and the client's domain — with the top listings beside it and the market on each page (price min, max, median, P25 and P75 with outliers over 2σ from the median, the top 10 sellers' share of listings, the share with free shipping and the rating distribution), and the client's position history for those keywords from every capture kept. A task still queued is listed as pending; ask again shortly. Answers 'where do we rank in Google Shopping' and 'who outranks us there'. Free: collecting a queued task costs nothing.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetShoppingSerpInput"
              },
              "example": {
                "clientId": "client_123",
                "tasks": [
                  {
                    "keyword": "carrier lookup",
                    "taskId": "examplex"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/audit_product_page": {
      "post": {
        "operationId": "audit_product_page",
        "summary": "Audit one product page",
        "description": "Reads one product page now and scores it 0–100 (a heuristic, said so in the answer) from six weighted parts, each check pass, warn or fail with the reason, or null when it cannot be judged (then left out and the weights rescaled): Product schema (25, the completeness validate_product_schema gives), title and meta (15: a title under 60 characters, a meta description under 155 with a price and a call to action), images (20: at least 3, each at least 50,000 pixels where the page declares sizes, alt text), content (20: 200 words or more, not the manufacturer's copy — pass manufacturerText to compare — a specifications table, reviews), linking (10: breadcrumbs, a link to its category, related products) and technical (10: status 200, indexable, a self canonical, a viewport, HTTPS). Answers 'what is wrong with this product page' and 'why does this product not rank'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuditProductPageInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_shopping_keyword_gap": {
      "post": {
        "operationId": "get_shopping_keyword_gap",
        "summary": "Organic rankings against Google Shopping presence",
        "description": "The client's ranked organic keywords (as last synced, top organicTop positions) and any keywords given, against whether its products showed in the Google Shopping pages captured by get_shopping_serp in the last days, in four groups, each with what to do: both (defend), organic_only (ranks but no product listed — list it in Merchant Center), shopping_only (a product listed but no organic ranking — build the page) and neither. Organic keywords never captured in Shopping are listed apart as unchecked, to queue with check_shopping_serp (paid). Matched on the seller names given (default the client's name) and the client's domain. Answers 'where do we rank but not sell in Shopping' and 'which Shopping keywords need a page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetShoppingKeywordGapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/score_amazon_listing": {
      "post": {
        "operationId": "score_amazon_listing",
        "summary": "Score an Amazon listing against the top results",
        "description": "Reads an Amazon product (by ASIN) and the listings ranking for a keyword, and scores the listing: title length and whether it carries the keyword, the bullet points (count and length), images, the terms the top titles share that this one lacks, and its rating, ratings count and price against the top listings' median. Each check pass, warn or fail with the reason. Answers 'how does our Amazon listing compare' and 'what should our title say'. Two reads from DataForSEO's Amazon data. A paid lookup on the client's account (spend says how much); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreAmazonListingInput"
              },
              "example": {
                "clientId": "client_123",
                "asin": "B08N5WRWNW",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/score_app_metadata": {
      "post": {
        "operationId": "score_app_metadata",
        "summary": "Score an app's store listing",
        "description": "Scores an App Store or Google Play listing for search: the title's length and whether it carries the target keywords, the subtitle (App Store) or short description (Play), the description's length and keyword use, screenshots, rating, ratings count and how recently it was updated — each pass, warn or fail with the reason — and, per keyword, where the listing uses it. App Store listings are read from Apple's free lookup API; a Play listing is read through DataForSEO's App Data, which queues the read: when it is not back within half a minute the answer is pending with a taskId to pass again. Answers 'how good is our app listing' and 'is our keyword in the title'. App Store: free. Google Play: A paid lookup on the client's account (spend says how much); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreAppMetadataInput"
              },
              "example": {
                "clientId": "client_123",
                "store": "app_store",
                "appId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_app_keyword_gap": {
      "post": {
        "operationId": "get_app_keyword_gap",
        "summary": "Keywords competitor apps rank for and ours does not",
        "description": "The store search keywords competitor apps rank for and the app does not, with search volume and each competitor's rank, from DataForSEO Labs (keywords for app; US English is what the vendor covers). With no competitors given, the vendor's own list of the app's competitors (top five) is used. Difficulty is not published for app keywords, so the best competitor rank stands in. Answers 'which keywords do rival apps rank for that we don't'. One read per app. A paid lookup on the client's account (spend says how much); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAppKeywordGapInput"
              },
              "example": {
                "clientId": "client_123",
                "store": "app_store",
                "appId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/mine_app_reviews": {
      "post": {
        "operationId": "mine_app_reviews",
        "summary": "What an app's reviews keep saying",
        "description": "Reads an app's recent reviews and mines them: the rating split, themes (crashes and bugs, performance, sign-in, ads, pricing and subscriptions, support, design, features) with how often each is raised and how negative, the phrases most repeated in 1–2 star reviews and in 4–5 star ones, and the feature requests. Works on a competitor's app as well as the client's. App Store reviews come free from Apple's public reviews feed (most recent 500); Google Play reviews through DataForSEO's App Data, queued: pending with a taskId to pass again when not back within half a minute. Answers 'what do users complain about', 'what do they love' and 'what are they asking for'. App Store: free. Google Play: A paid lookup on the client's account (spend says how much); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MineAppReviewsInput"
              },
              "example": {
                "clientId": "client_123",
                "store": "app_store",
                "appId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/youtube_keyword_research": {
      "post": {
        "operationId": "youtube_keyword_research",
        "summary": "YouTube search phrases around a topic",
        "description": "What people type into YouTube around a seed, in YouTube's own order of popularity (its suggestions; YouTube publishes no search volume, so none is given), and for the first measure phrases how crowded the results are: the top videos' median views, how many are from the last year, how many channels share them and how many are Shorts. Answers 'what should our next video target' and 'which YouTube phrases are winnable'. Suggestions are free; each phrase measured is one YouTube results page: A paid lookup on the client's account unless anyone read the same thing today (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/YoutubeKeywordResearchInput"
              },
              "example": {
                "clientId": "client_123",
                "seed": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/youtube_video_brief": {
      "post": {
        "operationId": "youtube_video_brief",
        "summary": "A title, description and chapter brief from the top videos",
        "description": "Reads the videos ranking on YouTube for a phrase (the results page, then each video's details) and writes the brief for a video to beat them: how their titles are built (length, the phrase first, numbers, brackets, the year) with examples, how long their descriptions run and how many use chapters and hashtags, the chapter labels they share in their usual order, the tags they use most, and how long the videos are. Answers 'how should we title and structure this video'. One results page plus one read per video: A paid lookup on the client's account unless anyone read the same thing today (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/YoutubeVideoBriefInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_youtube_channel_rankings": {
      "post": {
        "operationId": "get_youtube_channel_rankings",
        "summary": "Which of a channel's videos rank, for which phrases",
        "description": "For up to 20 phrases, reads YouTube's results and lists every video from the channel (matched by channel id, or by name) with its position and views, and the phrases where the channel does not appear. Works for the client's channel or a competitor's. For tracking over time, a rank tracker on the youtube engine does the same daily. Answers 'where do our videos rank' and 'which of their videos rank for our topics'. One results page per phrase: A paid lookup on the client's account unless anyone read the same thing today (spend says which); quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetYoutubeChannelRankingsInput"
              },
              "example": {
                "clientId": "client_123",
                "channel": "example",
                "keywords": [
                  "carrier lookup"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_seo_changes": {
      "post": {
        "operationId": "get_seo_changes",
        "summary": "What changed on the fields search engines read",
        "description": "Compares each page's status, robots directives (meta and X-Robots-Tag), canonical, hreflang, title, H1 and structured data types between two crawls (default: the latest and the one before), counted by field and by URL template, with every change listed. Critical: noindex added, canonical changed, title dropped, 200 to 404/5xx, hreflang lost, H1 rewritten (under half its words kept) — the changes that cost rankings within days, the first five of which each crawl also files as regression-* issues. Warning: meta description changed, Open Graph tags removed, structured data values changed (schema hash), a Core Web Vital p75 more than 20% worse in Chrome's field data, a template's Lighthouse performance down 10 points or more. Notice: H2 outline changed, page copy changed (body hash). The description, og, h2 and body fields compare only crawls that recorded them. fields, severity and template narrow it. Answers 'what did the last release break', 'did a template lose its canonicals' and 'why did these pages drop out'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSeoChangesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/check_deploy": {
      "post": {
        "operationId": "check_deploy",
        "summary": "Check a deploy before it ships",
        "description": "Fetches pages now and compares what they tell search engines (status, robots, canonical, hreflang, title, H1, structured data types; and, against crawls that recorded them, meta description, Open Graph tags, structured data values, H2 outline and copy) with the latest complete crawl's snapshot of the same paths, or the complete crawl baselineCrawlId names (from list_crawls), to compare against a crawl from before a release; baseline says which crawl was used and when it ran, and notes warns when the latest crawl started before the last recorded deploy (deploy hook or deploy annotation), so the baseline may already include that release. Give previewUrl (a deploy preview or staging origin: the crawl's pages, one or more per template, are fetched on that host, up to maxUrls) or urls (specific addresses, on production or a preview; matched by path). Canonicals and hreflang on the preview host are read as the production host, so only real changes show. passed is false when anything at or above failOn (default critical: noindex added, canonical changed, title dropped, a page now 4xx/5xx, hreflang lost, a page unreachable) changed; markdown is a ready pull-request comment. The client's set_crawl_auth credentials are sent to the preview host too, so a password-protected preview can be checked. Used by the Seolyticize GitHub Action. Answers 'will this deploy hurt SEO' and 'did the release noindex anything'. No vendor charge; it fetches pages on the client's behalf, so it needs project:manage.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckDeployInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/compare_sites": {
      "post": {
        "operationId": "compare_sites",
        "summary": "Compare staging with production",
        "description": "Fetches the same paths on two origins — staging (a) and production (b), say — and lists every difference in what they tell search engines: status, robots, canonical (read on each side's own host), hreflang, title, H1 and structured data, with critical ones first and a Markdown summary. Paths default to the client's latest crawl (its shallowest pages, spread across templates) or, without a crawl, the links on b's home page; paths narrows it. sendCrawlAuthTo sends the client's set_crawl_auth credentials (basic auth, headers, cookies) to that side only, for a password-protected staging site. When one side's home redirects to the other's host (www to the apex), redirect names the status and target and nothing is diffed, since that side has no pages of its own; single paths that redirect across are listed in redirected. followRedirect: true follows that redirect instead of stopping: each path on the redirecting side is fetched to where it lands and compared with the same path on the other side (the redirect's destination), redirectMap lists where each landed, and a path the redirect sends elsewhere (the home page, a 404) or a temporary redirect shows as a change; redirect stays reported and followedRedirect says it was followed. Answers 'is staging ready to go live', 'what will the migration change' and 'does www still redirect every page to the same path'. No vendor charge; it fetches pages on the client's behalf, so it needs project:manage.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompareSitesInput"
              },
              "example": {
                "clientId": "client_123",
                "a": "https://example.com/page",
                "b": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_robots_history": {
      "post": {
        "operationId": "get_robots_history",
        "summary": "How robots.txt and the sitemaps changed",
        "description": "The robots.txt each crawl read, newest first, with the lines added and removed against the version before (a new Disallow, a dropped Sitemap line), and per crawl how many sitemaps and entries were listed. Answers 'who changed robots.txt and when', 'why did Google stop crawling /blog' and 'did the sitemap shrink'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRobotsHistoryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/test_robots": {
      "post": {
        "operationId": "test_robots",
        "summary": "Can this bot fetch this page",
        "description": "Reads the client's live robots.txt and says, for each address and each crawler, whether it may fetch it and which line decides — for every search engine and AI crawler by default (Googlebot, Bingbot, Applebot, DuckDuckBot, YandexBot, Baiduspider, GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-SearchBot, Claude-User, PerplexityBot, Perplexity-User, Google-Extended, Applebot-Extended, Meta-ExternalAgent, Bytespider, CCBot, Amazonbot, DuckAssistBot, MistralAI-User, AhrefsBot, SemrushBot), or the tokens in bots. Same parser the crawler obeys. Answers 'can GPTBot read our pricing page', 'are we blocking Google-Extended' and 'which rule blocks Googlebot here'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestRobotsInput"
              },
              "example": {
                "clientId": "client_123",
                "urls": [
                  "https://example.com/page"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/validate_sitemap": {
      "post": {
        "operationId": "validate_sitemap",
        "summary": "Is the sitemap telling the truth",
        "description": "Checks the sitemaps a crawl read against the pages it found: entries that do not answer 200, are noindexed or are canonicalised elsewhere; indexable pages no sitemap lists (the sitemap's coverage of the crawl) and listed pages the crawl never reached (the crawl's coverage of the sitemap); lastmod accuracy against the previous crawl (content changed but lastmod did not, lastmod moved but nothing changed, dates in the future, every entry stamped with the build date); image and video sitemap coverage; and the entries added, removed and re-dated since the previous crawl. With checkFiles (default on) it also reads each sitemap file live, up to 20 — robots.txt's Sitemap: lines, the files the crawl read and what an index names — and judges each on its own: over 50,000 URLs or 50 MB uncompressed (critical), XML errors with their line number, not declared in robots.txt, http:// entries, <priority>/<changefreq> (ignored by Google), over 1,000 image:image per URL and the deprecated image tags, video entries missing thumbnail_loc, title, description or a content/player address, and news sitemaps over 1,000 entries, older than two days or missing publication name, language, date or title. Answers 'is our sitemap clean', 'does Google trust our lastmod' and 'which pages are missing from the sitemap'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateSitemapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/export_sitemap": {
      "post": {
        "operationId": "export_sitemap",
        "summary": "Write the sitemap from the latest audit",
        "description": "Writes sitemap.xml from the client's latest complete crawl: every 200 HTML page that is indexable and canonical to itself, deduplicated and sorted, with no lastmod (the crawl knows when it read a page, not when it changed). Past 50,000 URLs or 50 MB a file, it splits into sitemap-1.xml, sitemap-2.xml… under a sitemap.xml index whose locations assume the parts sit at the site's root. Returns a download link per file, valid for a day. Answers 'make us a clean sitemap' and 'what should our sitemap list'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportSitemapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/capture_page_screenshots": {
      "post": {
        "operationId": "capture_page_screenshots",
        "summary": "Screenshots and layout checks at four screen sizes",
        "description": "Renders one of the client's pages in a real browser at 1920×1080, 1366×768, 768×1024 and 375×812 (viewports narrows it), stores a PNG of each first screen (links last a day) and checks the layout there: whether the H1, the primary call to action and the hero image are above the fold, horizontal scrolling, tap targets under 24×24 px (fail) and under 48×48 (warn) — inline text links excepted — the base font size under 16px, overlapping controls and clipped text, and a fixed overlay covering over half the screen on load (cookie and consent banners excepted). parity (default on) also fetches the page as Googlebot smartphone and as desktop Chrome and compares words, links, headings and structured data types, since Google indexes the mobile version. Answers 'does the page work on a phone', 'is the CTA above the fold' and 'does Google's mobile crawler see the same page'. No vendor charge; it renders pages on the client's behalf, so it needs project:manage.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CapturePageScreenshotsInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_image_serp": {
      "post": {
        "operationId": "get_image_serp",
        "summary": "Who owns the image results for a keyword",
        "description": "Reads Google's organic results 100 deep for a keyword and every image pack in them: how many packs and where they sit, which domains hold the first ten images (and how dominant the top one is), the alt text pattern (how many have alt, average length, the share containing the keyword, the commonest words), the format mix (JPEG, WebP, AVIF…) and whether the client's site appears in a pack and where it ranks organically. Answers 'can we win image results for this', 'who dominates image search here' and 'how do the winners write their alt text'. Paid: a results page read 100 deep, billed per ten results; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetImageSerpInput"
              },
              "example": {
                "clientId": "client_123",
                "keyword": "carrier lookup"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/validate_structured_data": {
      "post": {
        "operationId": "validate_structured_data",
        "summary": "Structured data against Google's requirements",
        "description": "Checks JSON-LD against what Google's search gallery requires and recommends for each rich result type — Article, Breadcrumb, Course list (Course + ItemList), Carousel (ItemList), Dataset, Discussion forum, Event, Image metadata, Job posting, Local business, Movie, Organization, Product (snippets and merchant listings), Profile page, Q&A, Recipe, Review and rating, Software app, Vacation rental, Video, Site name — plus FAQ (retired for every site on 7 May 2026), HowTo, the 2025–2026 retirements (special announcement, fact check, vehicle listing, estimated salary, practice problem), Service and SoftwareSourceCode, which earn no rich result any more (or never did). Values Google cannot read (non-ISO dates and durations, prices with currency signs, relative URLs that are not URLs) are errors. Give url to read one of the client's pages live, or a crawlId (default latest) for the whole site by type: pages, how many are valid, and the properties most often missing. Answers 'is our product markup eligible for rich results' and 'what structured data is broken'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateStructuredDataInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_hreflang_report": {
      "post": {
        "operationId": "get_hreflang_report",
        "summary": "Hreflang across the site",
        "description": "Validates hreflang as clusters of pages rather than page by page, reading it from the pages and from xhtml:link entries in the sitemaps (and flagging where the two disagree): return links (a pair Google ignores because the other page does not name this one back), x-default, valid language-script-region codes (zh-Hant-TW is one; en-uk, es-EU, en-UN and es-LA are not; a bare country such as gb or us is not a language), self-reference, targets that redirect, error, are noindexed or are canonicalised elsewhere (canonical conflicts), hreflang on a page that is itself canonicalised away, and pages in a group naming different pages for one language. Answers 'is our hreflang set up correctly' and 'why does Google show the wrong language'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetHreflangReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_translation_gap": {
      "post": {
        "operationId": "get_translation_gap",
        "summary": "Pages missing in a language",
        "description": "Which pages exist in one language and not another: each indexable page's language (its hreflang, its /es/-style path prefix or its html lang), versions matched by hreflang or by the same path without the prefix, and for each language its coverage of the main language with the pages it lacks. Answers 'which pages have no Spanish version' and 'how complete is our /es site'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetTranslationGapInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_media_report": {
      "post": {
        "operationId": "get_media_report",
        "summary": "Images and video",
        "description": "Images and video across a crawl: alt text coverage, formats (and the share in AVIF or WebP), pages whose first image — usually the Largest Contentful Paint element — is lazy-loaded, how many images the image sitemap lists, embedded video with and without VideoObject markup and video sitemap coverage, plus the image checks' page counts. checkSizes asks the server for up to 100 image sizes (HEAD requests to the client's own hosts and its image CDNs) and lists the heaviest, with each judged against its role's band (thumbnail: target under 50KB, warn over 100KB, critical over 200KB; content: 100/200/500KB; hero, the page's first image: 200/300/700KB), and reads up to 20 product images' XMP for an IPTC DigitalSourceType that declares them AI-generated (trainedAlgorithmicMedia, compositeSynthetic, algorithmicMedia, compositeWithTrainedAlgorithmicMedia), and grades each image's browser caching (cache: long at a max-age of a week or more or immutable, short under a week, none with no-store, no-cache or no lifetime at all). Always: image hosts and the CDN each shows (by name, or by response headers when sizes are checked), the share on a separate host, and how pages lazy-load (native, perfmatters, EWWW, a generic script loader or none; script loaders are not reported as missing lazy loading). Answers 'are our images slowing the site down', 'which images lack alt text' and 'can our videos show in video results'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetMediaReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_security_report": {
      "post": {
        "operationId": "get_security_report",
        "summary": "Security headers and accessibility",
        "description": "Security and accessibility across a crawl: how many pages send HSTS (and with a weak max-age), a Content-Security-Policy and X-Content-Type-Options: nosniff, pages with mixed content (HTTP images, scripts, styles or frames on HTTPS), the security and accessibility checks' page counts, and the audit's Lighthouse runs with their accessibility and best-practices scores and failed accessibility audits — colour contrast first. Answers 'are our security headers set' and 'what accessibility problems does the site have'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSecurityReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_vitals_history": {
      "post": {
        "operationId": "get_vitals_history",
        "summary": "Core Web Vitals over 25 weeks",
        "description": "Core Web Vitals as Chrome measured them, week by week for the last 25 weeks, from the Chrome UX Report History API: p75 LCP, INP, CLS, TTFB and FCP (good at 1.8 s or less, poor over 3 s) for the client's origin, or one URL (url) when it has enough traffic, by form factor (phone, desktop or all). Regressions name a metric that got worse by more than 10% over the last four weeks or crossed into a worse rating; trends compare the first four weeks with the last four (within ±5% is stable). lcpBreakdown splits the newest image LCP into Chrome's four subparts (time to first byte, resource load delay, load duration, render delay) and names any at 40% of p75 LCP or more, with what to fix. Also the audits' Lighthouse runs per template, for the lab side. Without a Chrome UX Report key it says so and shows what is stored; nothing is estimated. Answers 'did our Core Web Vitals get worse', 'when did LCP regress' and 'are we passing on mobile'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetVitalsHistoryInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_site_conventions": {
      "post": {
        "operationId": "get_site_conventions",
        "summary": "Site-wide conventions: HSTS preload, slashes, rendering, share image",
        "description": "Four site-wide checks from a handful of live requests: whether the base domain qualifies for the HSTS preload list (max-age of a year or more, includeSubDomains, preload, http:// redirecting to https://; list membership itself is not checked); the trailing-slash convention, from up to samples crawled paths each asked for with and without the slash (one form redirecting to the other is consistent; both answering 200 is two addresses per page unless both name one canonical; some paths redirecting each way is mixed); dynamic rendering, suspected when Googlebot is served prerendered content and a browser an app shell with a fraction of the words (Google calls it a workaround, not a recommended solution); and the page's og:image, which should answer 200 and be at least 1200×630. url picks the page for the last two (default: the homepage). Answers 'are we ready for HSTS preload', 'do we have trailing-slash duplicates' and 'is our share image big enough'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSiteConventionsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_preload_readiness": {
      "post": {
        "operationId": "get_preload_readiness",
        "summary": "How ready a page is for instant navigation",
        "description": "A 0–100 heuristic from one page's markup and headers, 25 points each: speculation rules (a <script type=\"speculationrules\"> block or a Speculation-Rules header) for the next navigation; fetchpriority=\"high\" on the image that is probably the Largest Contentful Paint; nothing that keeps it out of the back/forward cache (Cache-Control: no-store, an unload listener); and no deprecated <link rel=\"prerender\">. With what to change for each part missed. A static reading, not a measurement: lab diagnostics come from page_lab. url defaults to the homepage and must be on the client's site. Answers 'can the next page load instantly' and 'why does Back reload the page'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPreloadReadinessInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_log_source": {
      "post": {
        "operationId": "connect_log_source",
        "summary": "Connect a server log feed",
        "description": "Connects a feed of the client's access logs so crawler reports stay current without uploads. kind: cloudflare-logpush (an HTTP destination for a Logpush http_requests job), cloudflare-worker (a Worker snippet for zones without Logpush), vercel (a log drain), fastly (an HTTPS logging endpoint, with the JSON format string to use), s3 (a bucket and prefix the worker pulls new objects from every hour — combined log format or Logpush NDJSON, gzipped or not; give s3 with read-only keys, stored encrypted) or upload (a URL to POST log files to). Returns the ingest URL (shown once: it carries the secret), the setup steps and any snippet. Only crawler requests are kept — visitors' requests are counted and dropped — and each crawler's claim is checked against reverse DNS or its published IP ranges. Answers 'stream our Cloudflare logs in' and 'set up a Vercel log drain'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectLogSourceInput"
              },
              "example": {
                "clientId": "client_123",
                "kind": "cloudflare-logpush"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_log_sources": {
      "post": {
        "operationId": "list_log_sources",
        "summary": "Connected log feeds",
        "description": "The client's connected log feeds: kind, when each last delivered, how many crawler requests it has stored and its last error (an S3 pull that was refused, say). Ingest URLs and keys are never shown again. Answers 'are our logs still arriving'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListLogSourcesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/revoke_log_source": {
      "post": {
        "operationId": "revoke_log_source",
        "summary": "Disconnect a log feed",
        "description": "Stops a log feed: its ingest URL refuses deliveries from now on, and an S3 source stops being pulled and its keys are deleted. Stored requests stay. Answers 'disconnect that log drain'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevokeLogSourceInput"
              },
              "example": {
                "clientId": "client_123",
                "sourceId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_crawl_budget": {
      "post": {
        "operationId": "get_crawl_budget",
        "summary": "Where crawlers spend their visits",
        "description": "From the client's connected logs over the last days (default 30): crawler requests by URL template (the site section, not the page), each with its share of all crawler requests, how much went on errors and redirects, and which crawlers; plus per crawler how many requests were verified (reverse DNS or published IP ranges), spoofed (claimed the name, failed the check — left out of every figure) or not checkable. Assets are left out. bot narrows to one crawler (googlebot, bingbot, gptbot…). Answers 'what is Googlebot wasting its time on' and 'how much of our crawl budget goes on parameter URLs'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetCrawlBudgetInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_crawler_activity": {
      "post": {
        "operationId": "get_ai_crawler_activity",
        "summary": "What AI crawlers read",
        "description": "From the client's connected logs: which pages GPTBot, ClaudeBot, PerplexityBot and every other AI agent fetched and how often — split by purpose (training crawls, search indexing, and fetches made for a user right now, the nearest a log gets to a citation) — with verified counts, error shares and when each was last seen. Google-Extended is a robots.txt opt-out token that Googlebot reads, not a crawler, so its robots.txt status is reported instead. Answers 'is ChatGPT reading our site', 'which pages does Perplexity fetch' and 'are AI crawlers hitting errors'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiCrawlerActivityInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_log_orphans": {
      "post": {
        "operationId": "get_log_orphans",
        "summary": "Pages crawlers find that the audit does not",
        "description": "Pages search and AI crawlers fetched successfully in the connected logs that the latest site crawl never reached — nothing on the site links to them, yet they are crawled (old campaigns, forgotten sections, pages only a sitemap or another site names) — with hits, which crawlers and when last seen. Answers 'which orphan pages is Google still crawling'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetLogOrphansInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/issue_server_collect_key": {
      "post": {
        "operationId": "issue_server_collect_key",
        "summary": "Key for server-side collection",
        "description": "Issues the secret key a server-side collector (@seolyticize/next/server, the Python and PHP collectors, or a POST to /api/collect with Authorization: Bearer) reports with, so it may send each visitor's own address and user agent (body fields ip and ua; howToUse lists the rest) — which is what lets it count people, and the AI assistants (ChatGPT-User, Claude-User, Perplexity-User) that never run the browser tag. Shown once; issuing another revokes the last. Answers 'track visits from our server' and 'count AI agents reading our pages'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueServerCollectKeyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_goal": {
      "post": {
        "operationId": "create_goal",
        "summary": "Define a conversion goal",
        "description": "Defines a goal for the cookieless analytics: reaching a page (kind pageview, match a path such as /thanks or /signup/*) or sending a custom event (kind event, match its name). Optionally worth a fixed value in minor units (2500 = 25.00); without one, an event's own 'value' property is summed. Counts every visit since the tag went in, not only from now. Answers 'count sign-ups as reaching /welcome'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGoalInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example",
                "kind": "pageview",
                "match": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_goals": {
      "post": {
        "operationId": "list_goals",
        "summary": "List conversion goals",
        "description": "The goals defined for a client's cookieless analytics, with what each matches and its value. Lists what get_goal_report counts; list_conversion_goals shows the custom events being sent. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListGoalsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_goal": {
      "post": {
        "operationId": "delete_goal",
        "summary": "Delete a goal",
        "description": "Deletes a goal. The events it counted are untouched. Answers 'stop counting that goal'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteGoalInput"
              },
              "example": {
                "clientId": "client_123",
                "goalId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_funnel": {
      "post": {
        "operationId": "create_funnel",
        "summary": "Define a funnel",
        "description": "Defines a funnel: 2 to 8 steps (a page reached or an event sent) a visit should pass through in order — landing page, product, cart, thank-you. Measured within one visit, because the cookieless visitor id resets daily. Pageview and event steps mix in any order; each step must happen after the one before it in the visit. Labels are optional and need not be unique (the report names a step by its label, else its match). Answers 'how many who see pricing go on to sign up'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFunnelInput"
              },
              "example": {
                "clientId": "client_123",
                "name": "example",
                "steps": [
                  {
                    "kind": "pageview",
                    "match": "example"
                  },
                  {
                    "kind": "pageview",
                    "match": "example"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_funnels": {
      "post": {
        "operationId": "list_funnels",
        "summary": "List funnels",
        "description": "Lists the funnels defined for a client, with their steps. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListFunnelsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_funnel": {
      "post": {
        "operationId": "delete_funnel",
        "summary": "Delete a funnel",
        "description": "Deletes a funnel definition. Answers 'remove that funnel'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteFunnelInput"
              },
              "example": {
                "clientId": "client_123",
                "funnelId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_goal_report": {
      "post": {
        "operationId": "get_goal_report",
        "summary": "Goals by channel, page or query",
        "description": "Visits, converting visits, conversions, conversion rate and value for each goal (default every goal), broken down by channel, landing page, source, campaign, the AI assistant that referred the visit, or the Search Console query cluster bringing people to the landing page. Answers 'which channel brings sign-ups', 'what is organic search worth in conversions', 'do visits from ChatGPT convert'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetGoalReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_funnel_report": {
      "post": {
        "operationId": "get_funnel_report",
        "summary": "Funnel steps and drop-off",
        "description": "How many visits reached each step of a funnel in order, with the share of the first step and of the step before, overall and per channel, landing page, source, campaign, AI referrer or query cluster. Answers 'where do people drop out between pricing and sign-up' and 'does search traffic finish the funnel'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetFunnelReportInput"
              },
              "example": {
                "clientId": "client_123",
                "funnelId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_ai_agent_visits": {
      "post": {
        "operationId": "get_ai_agent_visits",
        "summary": "AI assistants reading the site",
        "description": "How often AI assistants read the client's pages on somebody's behalf — ChatGPT-User, ChatGPT's agent mode, Claude-User, Perplexity-User, Mistral — by assistant, operator, page or day, seen by the tag or a server-side collector and kept apart from visits by people. Answers 'which pages is ChatGPT reading' and 'are assistants citing us more'. Training and index crawlers are not here: analyse_server_log reads those from the logs. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetAiAgentVisitsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_revenue_source": {
      "post": {
        "operationId": "connect_revenue_source",
        "summary": "Connect Stripe, Shopify or Paddle",
        "description": "Connects the client's own store so its orders can be counted against SEO. Stripe: a restricted key (rk_…) with read access to Charges and PaymentIntents — or use get_integration_connect_link for Stripe Connect. Shopify: the store's myshopify.com domain and a custom app's Admin API access token with read_orders — or the connect link for OAuth. Paddle: an API key with transaction.read (sandbox: true for a sandbox account). The key is checked, sealed, and the last 90 days imported straight away. Answers 'connect the client's Shopify'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectRevenueSourceInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "stripe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/import_revenue_now": {
      "post": {
        "operationId": "import_revenue_now",
        "summary": "Import orders now",
        "description": "Imports what changed in the client's connected stores since the last import (the nightly import does this on its own), attributing each order to the visit it came from. Answers 'pull in today's orders'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRevenueNowInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_seo_revenue": {
      "post": {
        "operationId": "get_seo_revenue",
        "summary": "Revenue by channel, page and query",
        "description": "Imported revenue (orders, revenue net of refunds, customers — per currency, never converted) by channel (organic search, AI assistants, paid, social, email, referral, direct, unattributed), landing page, Search Console query cluster, campaign, source, AI assistant or store, with how many orders were matched to their visit. Answers 'what is SEO worth in revenue', 'which pages and queries make money', 'what does ChatGPT send us in sales'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSeoRevenueInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/record_order": {
      "post": {
        "operationId": "record_order",
        "summary": "Record an order (no store connected)",
        "description": "Records one order for a business not on Stripe, Shopify or Paddle, so get_seo_revenue counts it: orderId (the site's own; recording it again replaces it, a replay is answered 'unchanged'), amountMinor in the currency's minor unit (4999 = 49.99 USD), currency, at (when paid) and, when the site kept one, visit — the visit token /api/collect gave its server collector while the buyer was on the site, which credits the order to that visit's landing page, source and channel. A refund is an order of its own with refundOf naming the order it refunds. Answers 'log this crypto payment against the visit it came from'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordOrderInput"
              },
              "example": {
                "clientId": "client_123",
                "orderId": "example",
                "amountMinor": 0,
                "currency": "usa",
                "at": "2026-10-01T00:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/record_orders": {
      "post": {
        "operationId": "record_orders",
        "summary": "Record orders in a batch",
        "description": "record_order for up to 500 orders in one call, for a server pushing its orders (POST /api/v1/tools/record_orders with an Idempotency-Key). Each is answered on its own — recorded, updated, unchanged or refused with the reason — and one refused order does not stop the rest. Refunds may refer to orders earlier in the same batch. Answers 'send last night's orders in one request'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordOrdersInput"
              },
              "example": {
                "clientId": "client_123",
                "orders": [
                  {
                    "orderId": "example",
                    "amountMinor": 0,
                    "currency": "usa",
                    "at": "2026-10-01T00:00:00Z"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/connect_integration": {
      "post": {
        "operationId": "connect_integration",
        "summary": "Connect Slack, Discord, Telegram, Airtable, a tracker or Matomo",
        "description": "Connects one of the client's own tools by token. Slack: webhookUrl (an incoming webhook), or token (a bot token, xoxb-…) with channel. Discord: webhookUrl. Telegram: token (from BotFather) with chatId. Airtable: token (a personal access token with data.records:read and write on the base). Jira: site (https://….atlassian.net), email, token (an API token), projectKey, optional issueType. Linear: token (a personal API key) and teamId. GitHub: token (fine-grained, Issues read and write), owner and repo. Matomo (analytics instead of GA4): site (the Matomo address, https://…), idSite (the site's id in Matomo) and token (a token_auth with view access, from Administration → Personal → Security; a POST-only token works); read with get_matomo_report. Checked with one call, then sealed. For Linear and GitHub it returns a webhook URL and secret to add in the tracker for instant status sync (polling hourly works without). Answers 'post the digest to our Slack', 'mirror tasks into Jira'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectIntegrationInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "airtable"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_integrations": {
      "post": {
        "operationId": "list_integrations",
        "summary": "A client's connected tools",
        "description": "Lists every outside service connected for the client — stores, sheets, Airtable, BigQuery, chats, trackers — with how it was connected, the key's last characters, when it last worked and its last error. Never the secret. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListIntegrationsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/disconnect_integration": {
      "post": {
        "operationId": "disconnect_integration",
        "summary": "Disconnect a tool",
        "description": "Removes a connection and its sealed key, with the syncs, digests and task links that ran through it. Revoke the key at the provider too. Answers 'disconnect their Stripe'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DisconnectIntegrationInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "stripe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_integration_connect_link": {
      "post": {
        "operationId": "get_integration_connect_link",
        "summary": "Link to connect by consent",
        "description": "A link that connects one of the client's accounts by signing in rather than pasting a key: Stripe (Connect, read-only), Shopify (OAuth; give shop), Slack (installs the app into a channel), Linear (OAuth; give teamId), Google Sheets or BigQuery (the client's Google account, with only that scope). Valid for ten minutes, for someone signed in to this agency. Answers 'connect the client's Google Sheets'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetIntegrationConnectLinkInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "stripe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_data_sync": {
      "post": {
        "operationId": "create_data_sync",
        "summary": "Sync data to a sheet, base or warehouse",
        "description": "Copies any dataset query (the query_data shape; see describe_datasets) to the client's Google Sheet (spreadsheetId, sheet), Airtable table (baseId, table — its fields named as the columns) or BigQuery table (projectId, datasetId, tableId — created on first run) on a schedule: daily, weekly or monthly at a UTC hour. replace swaps the contents each run; append adds rows, and with windowDays reads only the last N days ending yesterday so no day is added twice. Needs that destination connected first (get_integration_connect_link for Google, connect_integration for Airtable). Answers 'put our Search Console pages in a sheet every Monday', 'send the analytics to BigQuery daily'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataSyncInput"
              },
              "example": {
                "clientId": "client_123",
                "destination": "google_sheets",
                "name": "example",
                "query": {
                  "dataset": "gsc"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_data_syncs": {
      "post": {
        "operationId": "list_data_syncs",
        "summary": "List data syncs",
        "description": "Lists every scheduled data sync for the client: what it queries, where it writes, how often, when it last ran, how many rows and any error. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListDataSyncsInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/update_data_sync": {
      "post": {
        "operationId": "update_data_sync",
        "summary": "Change a data sync",
        "description": "Changes a sync's name, query, mode, window, cadence or hour, or pauses or resumes it; only what is passed changes. Answers 'make the sheet weekly' and 'pause the BigQuery export'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataSyncInput"
              },
              "example": {
                "clientId": "client_123",
                "syncId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_data_sync": {
      "post": {
        "operationId": "delete_data_sync",
        "summary": "Delete a data sync",
        "description": "Stops and removes a sync. What it already wrote stays where it is. Answers 'stop the Airtable sync'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteDataSyncInput"
              },
              "example": {
                "clientId": "client_123",
                "syncId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/run_data_sync_now": {
      "post": {
        "operationId": "run_data_sync_now",
        "summary": "Run a data sync now",
        "description": "Runs one sync immediately, outside its schedule, and says how many rows were written. Answers 'refresh the sheet now'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunDataSyncNowInput"
              },
              "example": {
                "clientId": "client_123",
                "syncId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/preview_weekly_digest": {
      "post": {
        "operationId": "preview_weekly_digest",
        "summary": "This week's digest",
        "description": "The weekly digest for the client as it would be posted, for the last complete Monday-to-Sunday week (week; the title names its days): what changed in Search Console, revenue and AI assistant visits; why it probably changed (demand, rankings, or particular pages); and the top five actions — from striking distance, low click-through, decaying pages and the latest audit — with the extra monthly clicks each is estimated to bring and, where revenue or goal values allow, what they are worth. Audit findings accepted as intentional (accept_issue) are left out and counted in basis; with path owners set, each audit action names its owner and byOwner groups them. Answers 'what should we do this week and why'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreviewWeeklyDigestInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/schedule_weekly_digest": {
      "post": {
        "operationId": "schedule_weekly_digest",
        "summary": "Post the weekly digest to a chat",
        "description": "Posts the weekly digest (see preview_weekly_digest) to the client's connected Slack, Discord or Telegram every week on a weekday (0 Sunday – 6 Saturday, default Monday) at a UTC hour. One schedule per chat connection; calling again changes it. Answers 'send Acme's weekly digest to their Slack on Mondays'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScheduleWeeklyDigestInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "slack"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_digest_schedules": {
      "post": {
        "operationId": "list_digest_schedules",
        "summary": "List digest schedules",
        "description": "Lists where and when the client's weekly digest is posted, and when it last went. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListDigestSchedulesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_digest_schedule": {
      "post": {
        "operationId": "delete_digest_schedule",
        "summary": "Stop a digest",
        "description": "Stops posting the weekly digest to that chat. Answers 'stop the Monday Slack digest'. Safe to repeat.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteDigestScheduleInput"
              },
              "example": {
                "clientId": "client_123",
                "digestId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/send_weekly_digest_now": {
      "post": {
        "operationId": "send_weekly_digest_now",
        "summary": "Post the digest now",
        "description": "Builds this week's digest and posts it to the client's connected Slack, Discord or Telegram straight away, outside any schedule. Answers 'send the digest to the channel now'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "report:send",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendWeeklyDigestNowInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "slack"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/push_tasks_to_tracker": {
      "post": {
        "operationId": "push_tasks_to_tracker",
        "summary": "Mirror tasks into Jira, Linear or GitHub",
        "description": "Creates an issue in the client's connected Jira project, Linear team or GitHub repository for each task (the chosen taskIds, or every task of the chosen statuses — default the open ones), with the task's notes and what it is about, and links the two so status syncs both ways. Tasks already mirrored there are skipped. dryRun: true creates nothing and lists wouldCreate (each issue's title and description) and alreadyLinked. Pairs with create_tasks_from_audit. Answers 'put the audit into our Jira'. Connect the tracker first with connect_integration. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushTasksToTrackerInput"
              },
              "example": {
                "clientId": "client_123",
                "provider": "jira"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/sync_task_statuses": {
      "post": {
        "operationId": "sync_task_statuses",
        "summary": "Sync task status with the tracker now",
        "description": "Reads every mirrored issue's state now and brings each pair into step: an issue moved in the tracker moves its task, a task moved here moves its issue (GitHub has no in-progress, so an open issue stays open). The hourly sync does this on its own. Answers 'did they close the Jira tickets'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SyncTaskStatusesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_task_links": {
      "post": {
        "operationId": "list_task_links",
        "summary": "Tasks mirrored in trackers",
        "description": "Lists which of the client's tasks are mirrored as issues, where (PROJ-12, ENG-34, #56, with links), and the tracker's state as last read. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListTaskLinksInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_seo_scorecard": {
      "post": {
        "operationId": "get_seo_scorecard",
        "summary": "SEO scorecard with an action plan",
        "description": "One 0–100 score for the site from its latest crawl (or crawlId), as seven weighted categories: Technical 22 (crawl, indexing, security and URL rules), Content 23 (thin and duplicate content, averaged with E-E-A-T over a sample of top pages), On-page 20 (titles, descriptions, headings, links, Open Graph), Schema 10 (structured-data rules and the share of pages with valid markup), Performance 10 (Chrome UX Report pass 100 / fail 50, averaged with the audit's Lighthouse runs), AI readiness 10 (the top pages' answer readiness) and Images 5. Each category says how it was measured, or that it was not (then the others are rescaled, never scored as zero), with its worst findings. Also the business type detected from the homepage and URLs (SaaS, local, ecommerce, publisher, agency; stored on the client brief), the five worst critical issues, five quick wins (warnings confined to one URL template, so one fix clears them) and a four-phase plan: critical issues in week 1, warnings in weeks 2–3, content and authority in month 2, then monitoring. Findings accepted as intentional (accept_issue) count against nothing and are listed in accepted with their reason. A heuristic beside the audit's health score, which is unchanged. Answers 'how is the site doing overall' and 'what should we fix first'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetSeoScorecardInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/audit_page": {
      "post": {
        "operationId": "audit_page",
        "summary": "Audit one page",
        "description": "Fetches one page of the client's site now and runs the crawler's full rule engine over it, plus page-level thresholds: title 30–60 characters, meta description 120–160, exactly one H1 and no skipped heading levels, og:title, og:description, og:image and og:url, twitter:card, twitter:title and twitter:description, alt text 10–125 characters, images over 200KB (warning) or 500KB (critical), and a word-count floor for the page type (home 500, service 800, primary location 600, secondary location 500, blog 1,500, product, category and about 400, landing 600, FAQ 800; pageType overrides the guess from the URL and markup), Flesch reading ease (60–70 suits a general audience; only under 30 is flagged, since it is not a ranking factor), query parameters in the URL (tracking parameters aside), links from the copy itself to the site's own pages against the page type's target (blog 5–10, service 3–5, product 2–4; navigation, header and footer links not counted), and templated metadata (a description that restates the title, closes on a stock call to action or repeats the title's brand suffix). Returns an overall score and five sub-scores (on-page, content, technical, schema, images; null where not measured), every issue by severity with its fix, and generate_schema's suggestions for the page. render 'auto' renders the page in a browser when its HTML looks like an unrendered shell. A heuristic. Answers 'what is wrong with this page' and 'is this page ready'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuditPageInput"
              },
              "example": {
                "clientId": "client_123",
                "url": "https://example.com/page"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/score_eeat": {
      "post": {
        "operationId": "score_eeat",
        "summary": "Score pages for E-E-A-T",
        "description": "Scores pages of the client's site (urls, up to 20, or the topPages by Search Console clicks) for Experience (20), Expertise (25), Authoritativeness (25) and Trust (30), each from sub-criteria graded Strong, Moderate, Weak or None with the evidence and the fix: first-hand method and results, figures, original images, a byline and author page, Person markup with jobTitle and sameAs, credentials, citations to outside and primary sources and the share of uncited claims, visible dates, about, contact, privacy and terms pages, HTTPS, reviews, a returns policy on shops, specialised vocabulary, awards and accreditations, 'featured in' media coverage, professional affiliations, a history of publishing on the topic (other crawled pages on it), visible corrections and update history, no deceptive practices (undisclosed affiliate links, clickbait headlines, false urgency), secure payments on shops, and for the site referring domains and brand mentions from our index and a Wikidata entity. Flags pages weak on who, how and why (atRisk), YMYL pages (health, finance, legal, news, civic, groups) with no credentials (Expertise capped at Weak), generic AI-style pages (one heading template, no author, stock phrasing), stale pages on fast-moving topics, and reading ease outside 60–70 (information only). Bands at 90/70/50/30, each page and the sample with the next steps for its band. A heuristic. judge: true regrades Experience with one metered Claude call (quote it with estimate_cost). Answers 'does our content show E-E-A-T' and 'which pages look untrustworthy'. Free without judge.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScoreEeatInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/draft_seo_strategy": {
      "post": {
        "operationId": "draft_seo_strategy",
        "summary": "Draft an SEO strategy",
        "description": "Drafts a 12-month SEO strategy for the client and saves it as a written report (save: false returns it without saving): a plan for its business type (SaaS, local, ecommerce, publisher or agency, as get_seo_scorecard detects it) in four phases — weeks 1–4, weeks 5–12, weeks 13–24 and months 7–12 — a teardown of the top five competitors (competitors, else the brief's and the ones we see ranking beside it) from the data we hold, a KPI table at baseline, 3, 6 and 12 months with baselines from Search Console and targets from forecast_search_clicks, plus indexed pages (URL Inspection, against the pages meant to be indexed) and phone Core Web Vitals (Chrome UX Report p75 against Google's good lines), the site structure from the latest crawl, the URL architecture and a schema plan by page type for the business type (no FAQPage, no self-serving ratings), and a calendar from plan_content (the stored plan, or a new one built when there is none). Every figure comes from the client's data and is named with its source; Claude writes the prose around them and invents none. instructions adds the agency's own direction. One metered Claude call: quote it with estimate_cost. Answers 'write us an SEO strategy' and 'what is the plan for this client this year'.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DraftSeoStrategyInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_matomo_report": {
      "post": {
        "operationId": "get_matomo_report",
        "summary": "Visits, pages and goals (Matomo)",
        "description": "For a client that measures with Matomo instead of GA4, read live from their Matomo. report: overview (visits, unique visitors when the server processes them for ranges, actions, pageviews, bounce rate, average time, conversions, conversion rate, revenue); channels (visits, bounce rate, conversions and revenue by referrer channel: search, social, ai, direct, website, campaign — Matomo's own split); landing_pages (entrances, bounce rate, actions per entrance, conversions and revenue credited to the entry page); pages (pageviews, visits, average time, bounce and exit rate by page URL); goals (conversions, conversion rate and revenue per goal, and in total). channel limits overview, landing_pages, pages and goals to search engines (organic) or AI assistants (ai) through a Matomo segment; Matomo answers a segment only once it has processed it, and says so. Compares with the same number of days before unless compare is false; defaults to the 28 days ending yesterday. Rows carry key, label, current and previous (null where that period had no row). Figures Matomo did not send are null, never zero. Refuses with a sentence when Matomo is not connected (connect_integration with provider matomo). Answers 'is organic traffic growing' and 'which landing pages convert' for a Matomo site. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetMatomoReportInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/add_default_alerts": {
      "post": {
        "operationId": "add_default_alerts",
        "summary": "Add the default alerts",
        "description": "Gives a client the four alerts every new client now starts with: the site goes down (site-unreachable), non-branded Search Console clicks fall 30% or more week on week (traffic-drop 30), a crawl finds critical issues (new-critical-issues 1), and a tracked keyword drops 5 or more places (rank-drop 5). Each goes to the agency owner's email until changed with update_alert_rule. A kind the client already has a rule for is kept as it is, so it is safe to repeat. channel with webhookUrl (slack, webhook, discord), emailRecipients (email) or telegramChatId (telegram) sends them there instead, and moves default rules still going only to the owner's email (moved). include: [\"page-changes\"] adds a fifth: own pages whose title, meta description, H1 or canonical changed, went noindex or 404. Pass clientId for one client, or allClients: true for every live client the key may manage. Answers 'set up the usual alerts'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddDefaultAlertsInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_crawl_schedule": {
      "post": {
        "operationId": "set_crawl_schedule",
        "summary": "Set when the site is crawled",
        "description": "Sets how often the client's site is crawled without anyone asking: off, daily, weekly or monthly; weekly on Monday at 02:00 UTC unless changed. day is the weekday for weekly (0 Sunday to 6 Saturday; default 1, Monday) or the day of the month for monthly (1–28; default 1); hour is the UTC hour (default 2). Scheduled crawls use the client's crawl settings and wait their turn in the crawl queue like any other; one is never started while another crawl of the site is running, and a crawl started by hand since the last slot counts as that slot's. get_crawl_settings shows the schedule and when it next runs. Answers 'crawl this site every night'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "project:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetCrawlScheduleInput"
              },
              "example": {
                "clientId": "client_123",
                "cadence": "off"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/accept_issue": {
      "post": {
        "operationId": "accept_issue",
        "summary": "Accept an audit issue as intentional",
        "description": "Marks one audit rule's findings as kept on purpose, on the pages of a URL template (template: /login, /legal/*, /docs/*?sort=*; * is one path segment, a final ** the rest; a template without a query matches any query) or on listed addresses (urls), with the reason and, optionally, the last day it holds (until, YYYY-MM-DD). From then on those findings leave get_seo_scorecard, the counts of get_audit_summary (shown apart as accepted, each with its reason), the weekly digest, create_tasks_from_audit and the alerts; list_issue_pages marks them. ruleId comes from get_audit_summary. matchedNow is how many of the latest crawl's findings of the rule it covers, out of rulePages (both null without a crawl), with a sample of the covered addresses; warning is set when it covers nothing, or when a template covers more than half the rule's pages (likely too broad). dryRun: true saves nothing and answers the same coverage, to check a template first. Examples: login pages noindexed by design, old versions of the legal pages, sort variants. unaccept_issue undoes it. Answers 'stop flagging our login pages, they are noindexed on purpose'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptIssueInput"
              },
              "example": {
                "clientId": "client_123",
                "ruleId": "example",
                "reason": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_accepted_issues": {
      "post": {
        "operationId": "list_accepted_issues",
        "summary": "List the issues accepted as intentional",
        "description": "The client's accepted audit findings: rule, template or addresses, the reason, until and who accepted it. includeLapsed adds the ones whose until has passed, which count again. Answers 'what have we decided to ignore, and why'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListAcceptedIssuesInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/unaccept_issue": {
      "post": {
        "operationId": "unaccept_issue",
        "summary": "Stop accepting an issue",
        "description": "Removes acceptances by id (from list_accepted_issues), so their findings count again in the scorecard, audit summary, digest, tasks and alerts. Unknown ids are ignored. Answers 'start flagging those pages again'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnacceptIssueInput"
              },
              "example": {
                "clientId": "client_123",
                "ids": [
                  "example"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_path_owners": {
      "post": {
        "operationId": "set_path_owners",
        "summary": "Say who owns which part of the site",
        "description": "For a site built on several platforms, names the owner (and a contact) of each path prefix: /docs, /blog and /community on one vendor, the shop on another. mode replace (the default) makes owners the client's whole list, and an empty list clears it; mode merge adds or updates the prefixes given, drops those in remove, and keeps every other. The answer lists the resulting owners and the changes: added, updated (with what it was), removed and kept. dryRun: true saves nothing and answers the same, to check a change first. A URL belongs to the longest prefix it falls under, on segment boundaries (/docs covers /docs/x, not /docsearch); / is the catch-all. Then get_audit_summary and list_issue_pages split issues by owner, create_tasks_from_audit puts the owner on each task, and the digest groups its fixes by owner. Answers 'the docs team owns /docs, send those fixes to them'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:write",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPathOwnersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_path_owners": {
      "post": {
        "operationId": "list_path_owners",
        "summary": "List who owns which part of the site",
        "description": "The client's path owners from set_path_owners: prefix, owner and contact, shortest prefix first. Answers 'who fixes issues on /docs'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListPathOwnersInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_vendor_reconciliation": {
      "post": {
        "operationId": "get_vendor_reconciliation",
        "summary": "Reconcile vendor spend against the ledger",
        "description": "Sets the agency's DataForSEO account (deposited, balance, spent; today's spend per API) beside what Seolyticize's cost ledger recorded on the same account, with the difference, the ledger by operation, and what can explain a gap: spend before the ledger began, the same login used outside Seolyticize, other agencies sharing it. Answers 'why did our DataForSEO balance fall more than get_costs shows'. agreesWithinCents is true when the two agree to a cent. Reads the account from DataForSEO's free user_data endpoint. On the platform's shared key, only a platform admin may reconcile. Amounts are US dollars. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "cost:view",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetVendorReconciliationInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/estimate_cost": {
      "post": {
        "operationId": "estimate_cost",
        "summary": "Estimate what a call will cost",
        "description": "Quotes the most a tool call can cost before it is made, without buying anything. Answers 'how much will this cost'. Pass the tool's name and the exact arguments you would call it with; the result lists each purchase the call can make with its ceiling, plus monthlyMicros for scheduled work. Show the estimate to the user before a paid call, then pass estimatedMaxMicros as that call's maxCostMicros so it cannot spend more. Cached data costs nothing, so real charges are often lower. A paid quote also says vendorReady and vendorBalanceMicros: vendorReady false (with the code the call would fail with, such as vendor_balance_empty) means the purchase cannot be made right now. Also quotes \"rank_tracker\": a rank tracker's captures (arguments: clientId, trackerId) — per run and per month. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EstimateCostInput"
              },
              "example": {
                "tool": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/find_tools": {
      "post": {
        "operationId": "find_tools",
        "summary": "Find the tools for a task",
        "description": "Given a task in plain words ('why did traffic drop', 'write an article about X', 'who links to my rivals'), returns the 5–10 tools for it, best first, each with what it does and whether it costs money — and the named recipe that covers the task, when one does. Use it instead of reading the whole catalogue. Answers 'which tool do I use for this'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FindToolsInput"
              },
              "example": {
                "task": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_recipe": {
      "post": {
        "operationId": "get_recipe",
        "summary": "A named plan of calls",
        "description": "An ordered call plan for a common job, with arguments filled in from the client (its domain, rivals, a keyword it ranks for) and the ones left to fill named in fill. Recipes: weekly_review, new_article, technical_audit, site_migration, competitor_teardown, ai_visibility_baseline. A plan, not automation: make each call, read it, and skip a step the one before says is unnecessary. With no name, lists them. Answers 'what's the process for a technical audit'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetRecipeInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_price_list": {
      "post": {
        "operationId": "get_price_list",
        "summary": "What everything costs",
        "description": "Every paid data operation with its most-per-request price in micro-USD and how long an answer stays free once anyone has bought it (the shared archive), plus which tools spend. A tool's own quote for given arguments is estimate_cost, or the tool itself with dryRun: true. Answers 'how much does this cost' and 'what is cached for how long'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetPriceListInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_budget": {
      "post": {
        "operationId": "set_budget",
        "summary": "Set a client's monthly budget and alert",
        "description": "Sets a client's monthly spending budget in USD (null removes it; paid calls past it are refused) and the share of it, 0–1, at which a budget.threshold event and alert fire once that month (null turns the alert off). Leave either out to keep it. A per-call ceiling belongs to an API key: create_api_key's maxCostUsdPerCall. Answers 'cap this client at $50 a month and warn me at 80%'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetBudgetInput"
              },
              "example": {
                "clientId": "client_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/set_domain_sweep": {
      "post": {
        "operationId": "set_domain_sweep",
        "summary": "Turn the weekly domain refresh on or off",
        "description": "Turns the Sunday 01:00 UTC domain sweep on or off for one client: the weekly paid refresh of its domain overview, ranked keywords, competitors, top pages and backlinks. It is off for new clients (onboarding schedules no paid work by itself) and on for clients made before 2026-11-02; get_budget_status shows what it costs a month and who turned it on (projection.items[].enabledBy). refresh_domain_data still runs it by hand. Answers 'stop the weekly backlink refresh'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "client:manage",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetDomainSweepInput"
              },
              "example": {
                "clientId": "client_123",
                "enabled": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_job": {
      "post": {
        "operationId": "get_job",
        "summary": "How a slow job is going",
        "description": "One way to follow anything slow — a crawl, a rank or domain refresh, a performance run: its status (queued, running, done, failed), progress, an ETA where one can be told, and the tool that reads the finished result. jobId is kind:id — crawl:<crawlId> (from start_crawl), rank:<runId> (refresh_rankings), domain:<runId> (refresh_domain_data), performance:<runId>. An AI visibility check reports through get_ai_visibility_runs. Answers 'is my crawl done'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetJobInput"
              },
              "example": {
                "clientId": "client_123",
                "jobId": "crawl:cr_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/wait_for_job": {
      "post": {
        "operationId": "wait_for_job",
        "summary": "Wait for a slow job",
        "description": "get_job that waits: holds the call open until the job finishes or timeoutSeconds pass (at most 60), then answers with its status, so an agent makes one call instead of polling. Call again while it says running. Answers 'wait for the crawl'. Free.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WaitForJobInput"
              },
              "example": {
                "clientId": "client_123",
                "jobId": "crawl:cr_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/create_webhook": {
      "post": {
        "operationId": "create_webhook",
        "summary": "Subscribe a URL to events",
        "description": "Sends events to an https URL as they happen, signed: each POST carries Seolyticize-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<body>\" with the secret>, plus Seolyticize-Event and Seolyticize-Delivery headers. Retried with backoff (1 min to a day) until a 2xx; replay_webhooks sends missed ones again. Events: crawl.completed, gsc.synced, rank.moved, backlink.new, backlink.lost, issue.new_critical, ai.citation.gained, ai.citation.lost, competitor.page.new, budget.threshold, alert.fired, vendor.balance_low, vendor.balance_empty. vendor.balance_low and vendor.balance_empty fire at most once a week while the balance stays low, not once per crossing. clientId limits it to one client; null is every client. The secret is in the response once. Answers 'tell my system when a crawl finishes'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookInput"
              },
              "example": {
                "url": "https://example.com/page",
                "events": [
                  "crawl.completed"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_webhooks": {
      "post": {
        "operationId": "list_webhooks",
        "summary": "List webhooks",
        "description": "The agency's webhooks: URL, events, client, and whether one was switched off after failing for too long. Answers 'what webhooks do we have'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListWebhooksInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/delete_webhook": {
      "post": {
        "operationId": "delete_webhook",
        "summary": "Delete a webhook",
        "description": "Stops a webhook for good, with its queued deliveries. Answers 'stop sending to that URL'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DeleteWebhookInput"
              },
              "example": {
                "webhookId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/list_webhook_deliveries": {
      "post": {
        "operationId": "list_webhook_deliveries",
        "summary": "A webhook's deliveries",
        "description": "A webhook's recent deliveries, newest first: event, status, attempts, the receiver's last HTTP status and error. Answers 'why isn't my webhook receiving anything'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListWebhookDeliveriesInput"
              },
              "example": {
                "webhookId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/replay_webhooks": {
      "post": {
        "operationId": "replay_webhooks",
        "summary": "Send events again",
        "description": "Queues events for a webhook again: one delivery (deliveryId), or every subscribed event since an ISO time (default: the last 24 hours). For a receiver that was down. Answers 'resend what we missed'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplayWebhooksInput"
              },
              "example": {
                "webhookId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/send_test_event": {
      "post": {
        "operationId": "send_test_event",
        "summary": "Send a test event",
        "description": "Queues an alert.fired test event to one webhook, delivered within a minute, so a receiver's signature check can be tried end to end. Answers 'test my webhook'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "api:manage",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTestEventInput"
              },
              "example": {
                "webhookId": "example"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/get_error_catalogue": {
      "post": {
        "operationId": "get_error_catalogue",
        "summary": "What every error code means",
        "description": "Every refusal code the API returns, with what it means and what to do about it — the same list as GET /api/v1/errors. Answers 'what does spend_cap_exceeded mean'. Free.",
        "tags": [
          "Agency"
        ],
        "x-seolyticize-permission": "data:read",
        "x-seolyticize-client-scoped": false,
        "x-seolyticize-read-only": true,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GetErrorCatalogueInput"
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/tools/explain_result": {
      "post": {
        "operationId": "explain_result",
        "summary": "Explain a result in plain words",
        "description": "Reads any earlier tool result (pass the tool's name and its data) and says, in plain language for a client or for the team, what it shows, what matters in it and what to do next — for handing off to people who don't read JSON. Answers 'what does this mean for the client'. A metered Claude call on the client's budget; quote it with estimate_cost.",
        "tags": [
          "Client"
        ],
        "x-seolyticize-permission": "spend:incur",
        "x-seolyticize-client-scoped": true,
        "x-seolyticize-read-only": false,
        "x-seolyticize-destructive": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExplainResultInput"
              },
              "example": {
                "clientId": "client_123",
                "tool": "example",
                "result": null
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The tool's result under `data`, and its meta.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-Request-Id": {
                "$ref": "#/components/headers/RequestId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "meta"
                  ],
                  "properties": {
                    "data": {},
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/v1/errors": {
      "get": {
        "operationId": "listErrors",
        "summary": "Every error code",
        "description": "Every refusal code with what it means and what to do. Public.",
        "security": [],
        "responses": {
          "200": {
            "description": "The catalogue."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sk_seo_…",
        "description": "An API key created under Settings, or with the create_api_key tool. A key is agency-wide or pinned to one client, and carries a role that decides which tools it may call."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Any unique string, up to 200 characters. A retry with the same key and body is answered from the first answer (Idempotent-Replayed: true) for a day, so it never buys or writes twice; the same key with another body is refused.",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      }
    },
    "headers": {
      "RequestId": {
        "description": "The id to quote about this request.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimitLimit": {
        "description": "Requests this key may make per window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until the current window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The body was not JSON or did not match the tool's input schema.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No key, or a key that is unknown or revoked.",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key's role does not permit the tool, or the key may not reach the named client.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No tool by that name.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Refused": {
        "description": "A well-formed request the product declined, with the reason — a duplicate name, a plan limit, nothing configured to run.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "This key has used its window.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "The request could not be completed.",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A sentence written for the caller. Internal failures are reduced to 'The request could not be completed.' and never carry detail."
          },
          "code": {
            "type": "string",
            "description": "A stable snake_case reason to branch on; GET /api/v1/errors lists them all."
          },
          "next": {
            "type": "string",
            "description": "The call or step that fixes it, when there is one."
          },
          "requestId": {
            "type": "string",
            "description": "Quote it when asking about a failure."
          }
        }
      },
      "Meta": {
        "type": "object",
        "required": [
          "requestId",
          "costMicros",
          "cached",
          "partial",
          "next"
        ],
        "description": "Beside every answer: what it cost, whether it came from cache, how fresh it is, whether it is complete, and what to call next.",
        "properties": {
          "requestId": {
            "type": [
              "string",
              "null"
            ]
          },
          "costMicros": {
            "type": "integer",
            "description": "Charged by this call, micro-USD (1,000,000 = $1)."
          },
          "cached": {
            "type": "boolean",
            "description": "True when nothing was bought."
          },
          "cachedFrom": {
            "type": [
              "string",
              "null"
            ],
            "description": "When the oldest cached answer used was bought."
          },
          "dataAsOf": {
            "type": [
              "string",
              "null"
            ]
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "partial": {
            "type": "boolean",
            "description": "True when the data is incomplete: a running crawl, unfinished days, unread pages."
          },
          "next": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tool": {
                  "type": "string"
                },
                "args": {
                  "type": "object"
                },
                "why": {
                  "type": "string"
                }
              }
            }
          },
          "nextCursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as cursor for the next page."
          },
          "dryRun": {
            "type": "boolean"
          }
        }
      },
      "ToolDescriptor": {
        "type": "object",
        "required": [
          "name",
          "title",
          "description",
          "permission",
          "clientScoped",
          "readOnly",
          "destructive",
          "spends",
          "path",
          "inputSchema"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "permission": {
            "type": "string"
          },
          "clientScoped": {
            "type": "boolean"
          },
          "readOnly": {
            "type": "boolean"
          },
          "destructive": {
            "type": "boolean"
          },
          "spends": {
            "type": "boolean"
          },
          "path": {
            "type": "string"
          },
          "inputSchema": {
            "type": "object"
          }
        }
      },
      "ListClientsInput": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          }
        },
        "additionalProperties": false
      },
      "GetRankSummaryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetShareOfVoiceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetPanelReachInput": {
        "type": "object",
        "properties": {
          "hosts": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "from": {
            "type": "string",
            "minLength": 10
          },
          "to": {
            "type": "string",
            "minLength": 10
          }
        },
        "required": [
          "hosts",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "SubmitUrlsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "ListRecentAlertsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "since": {
            "type": "string",
            "minLength": 10
          }
        },
        "required": [
          "clientId",
          "since"
        ],
        "additionalProperties": false
      },
      "GetKeywordDifficultyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "clientId",
          "keywordIds"
        ],
        "additionalProperties": false
      },
      "GetKeywordGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "competitorDomains": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "clientId",
          "competitorDomains"
        ],
        "additionalProperties": false
      },
      "GetContentGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "competitorDomains": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "clientId",
          "competitorDomains"
        ],
        "additionalProperties": false
      },
      "GetLinkIntersectInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "competitorDomains": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "clientId",
          "competitorDomains"
        ],
        "additionalProperties": false
      },
      "GetCannibalizationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetContentDecayInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAuditSummaryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          },
          "indexableOnly": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListIssuePagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "indexableOnly": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "ruleId"
        ],
        "additionalProperties": false
      },
      "GetPageIssuesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "BatchDomainMetricsInput": {
        "type": "object",
        "properties": {
          "domains": {
            "minItems": 1,
            "maxItems": 2000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "domains"
        ],
        "additionalProperties": false
      },
      "PageVitalsInput": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": false
      },
      "PageHeadersInput": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": false
      },
      "GetSearchDemandInput": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "market": {
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "since": {
            "type": "string",
            "minLength": 10
          }
        },
        "required": [
          "query",
          "market",
          "since"
        ],
        "additionalProperties": false
      },
      "GetClickCurveInput": {
        "type": "object",
        "properties": {
          "engine": {
            "default": "google",
            "type": "string",
            "minLength": 2,
            "maxLength": 32
          },
          "market": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "query": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "additionalProperties": false
      },
      "GetTopSearchesInput": {
        "type": "object",
        "properties": {
          "market": {
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "since": {
            "type": "string",
            "minLength": 10
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "market",
          "since"
        ],
        "additionalProperties": false
      },
      "PageLabInput": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "strategy": {
            "default": "mobile",
            "type": "string",
            "enum": [
              "mobile",
              "desktop"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": false
      },
      "GetEntityPageviewsInput": {
        "type": "object",
        "properties": {
          "entity": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "language": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 12
          },
          "granularity": {
            "default": "monthly",
            "type": "string",
            "enum": [
              "daily",
              "monthly"
            ]
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{8}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{8}$"
          }
        },
        "required": [
          "entity",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "SubmitIndexnowInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "GetDomainFactsInput": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 1,
            "maxLength": 253
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "domain"
        ],
        "additionalProperties": false
      },
      "KeywordExplorerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seed": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "mode": {
            "default": "ideas",
            "type": "string",
            "enum": [
              "ideas",
              "suggestions",
              "related",
              "questions"
            ]
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "filters": {
            "default": {},
            "type": "object",
            "properties": {
              "include": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                }
              },
              "includeMode": {
                "type": "string",
                "enum": [
                  "all",
                  "any"
                ]
              },
              "exclude": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                }
              },
              "volumeMin": {
                "type": "number",
                "minimum": 0
              },
              "volumeMax": {
                "type": "number",
                "minimum": 0
              },
              "difficultyMin": {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "difficultyMax": {
                "type": "number",
                "minimum": 0,
                "maximum": 100
              },
              "cpcMinUsd": {
                "type": "number",
                "minimum": 0
              },
              "cpcMaxUsd": {
                "type": "number",
                "minimum": 0
              },
              "wordsMin": {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991
              },
              "wordsMax": {
                "type": "integer",
                "minimum": 1,
                "maximum": 9007199254740991
              },
              "questionsOnly": {
                "type": "boolean"
              },
              "intents": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "informational",
                    "navigational",
                    "commercial",
                    "transactional"
                  ]
                }
              },
              "serpFeatures": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "featured_snippet",
                    "people_also_ask",
                    "local_pack",
                    "video",
                    "image_pack",
                    "shopping",
                    "knowledge_panel",
                    "site_links",
                    "top_stories",
                    "related_searches",
                    "ai_overview"
                  ]
                }
              }
            }
          },
          "sort": {
            "default": {
              "key": "volume",
              "direction": "desc"
            },
            "type": "object",
            "properties": {
              "key": {
                "type": "string",
                "enum": [
                  "volume",
                  "difficulty",
                  "cpc",
                  "term",
                  "words"
                ]
              },
              "direction": {
                "default": "desc",
                "type": "string",
                "enum": [
                  "asc",
                  "desc"
                ]
              }
            },
            "required": [
              "key"
            ]
          },
          "page": {
            "default": 1,
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "pageSize": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "format": {
            "default": "rows",
            "type": "string",
            "enum": [
              "rows",
              "csv"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "seed"
        ],
        "additionalProperties": false
      },
      "SerpOverviewInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "term": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "refresh": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "term"
        ],
        "additionalProperties": false
      },
      "KeywordTrafficPotentialInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "term": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "refresh": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "term"
        ],
        "additionalProperties": false
      },
      "StrikingDistanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 480
          },
          "minPosition": {
            "default": 4,
            "type": "number",
            "minimum": 1,
            "maximum": 100
          },
          "maxPosition": {
            "default": 20,
            "type": "number",
            "minimum": 1,
            "maximum": 100
          },
          "minImpressions": {
            "default": 50,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ExplainKeywordDifficultyInput": {
        "type": "object",
        "properties": {
          "term": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "keywordId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          }
        },
        "required": [
          "term"
        ],
        "additionalProperties": false
      },
      "ListKeywordListsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "additionalProperties": false
      },
      "CreateKeywordListInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "keywords": {
            "default": [],
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "term": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "locationCode": {
                  "default": 2840,
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "languageCode": {
                  "default": "en",
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 8
                },
                "engine": {
                  "default": "google",
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 32
                },
                "metrics": {
                  "description": "Metrics already bought for this keyword — from keyword_explorer or get_keyword_metrics, in their units (CPC in micro-USD) — stored on the list so they need not be bought again. Fields left out are not given; on a keyword already on the list only the given fields change.",
                  "type": "object",
                  "properties": {
                    "searchVolume": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "difficulty": {
                      "anyOf": [
                        {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 100
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cpcMicros": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "competition": {
                      "anyOf": [
                        {
                          "type": "number",
                          "minimum": 0
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "intent": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "informational",
                            "navigational",
                            "commercial",
                            "transactional"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "serpFeatures": {
                      "anyOf": [
                        {
                          "maxItems": 40,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "observedAt": {
                      "description": "When the figures were read. Default: now.",
                      "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)))$"
                    }
                  }
                }
              },
              "required": [
                "term"
              ]
            }
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "AddKeywordsToListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "term": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "locationCode": {
                  "default": 2840,
                  "type": "integer",
                  "minimum": -9007199254740991,
                  "maximum": 9007199254740991
                },
                "languageCode": {
                  "default": "en",
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 8
                },
                "engine": {
                  "default": "google",
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 32
                },
                "metrics": {
                  "description": "Metrics already bought for this keyword — from keyword_explorer or get_keyword_metrics, in their units (CPC in micro-USD) — stored on the list so they need not be bought again. Fields left out are not given; on a keyword already on the list only the given fields change.",
                  "type": "object",
                  "properties": {
                    "searchVolume": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "difficulty": {
                      "anyOf": [
                        {
                          "type": "number",
                          "minimum": 0,
                          "maximum": 100
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "cpcMicros": {
                      "anyOf": [
                        {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 9007199254740991
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "competition": {
                      "anyOf": [
                        {
                          "type": "number",
                          "minimum": 0
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "intent": {
                      "anyOf": [
                        {
                          "type": "string",
                          "enum": [
                            "informational",
                            "navigational",
                            "commercial",
                            "transactional"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "serpFeatures": {
                      "anyOf": [
                        {
                          "maxItems": 40,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 60
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "observedAt": {
                      "description": "When the figures were read. Default: now.",
                      "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)))$"
                    }
                  }
                }
              },
              "required": [
                "term"
              ]
            }
          }
        },
        "required": [
          "listId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "RemoveKeywordsFromListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "listId",
          "keywordIds"
        ],
        "additionalProperties": false
      },
      "TagKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "tags": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40
            }
          },
          "remove": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "keywordIds",
          "tags"
        ],
        "additionalProperties": false
      },
      "GetRankHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetSerpFeaturesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetPositionDistributionInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetUrlSwapsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetSearchConsolePerformanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "searchType": {
            "default": "web",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "country": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z]{3}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "device": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "DESKTOP",
                  "MOBILE",
                  "TABLET"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "dimensions": {
            "default": [
              "date",
              "query",
              "page"
            ],
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "date",
                "query",
                "page",
                "country",
                "device"
              ]
            }
          },
          "page": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ]
          },
          "query": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "InspectUrlInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetIndexCoverageInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SyncSearchConsoleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListSitemapsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SubmitSitemapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sitemapUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "sitemapUrl"
        ],
        "additionalProperties": false
      },
      "DeleteSitemapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sitemapUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "sitemapUrl"
        ],
        "additionalProperties": false
      },
      "GetBingPerformanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetYandexPerformanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "SubmitBaiduUrlsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "SubmitYandexRecrawlInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "ExportSearchConsoleDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "searchType": {
            "default": "web",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "country": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z]{3}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "device": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "DESKTOP",
                  "MOBILE",
                  "TABLET"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "dimension": {
            "default": "query",
            "type": "string",
            "enum": [
              "query",
              "page"
            ]
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "SaveBaiduTokenInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "siteUrl": {
            "type": "string",
            "format": "uri"
          },
          "token": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        },
        "required": [
          "clientId",
          "siteUrl",
          "token"
        ],
        "additionalProperties": false
      },
      "GetSearchConsoleHourlyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "searchType": {
            "default": "web",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "days": {
            "default": 3,
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetClientBriefInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "UpdateClientBriefInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "overview": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "goal": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "positioning": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "audience": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "voice": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "add": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "competitor",
                    "key_page",
                    "section",
                    "research"
                  ]
                },
                "title": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "body": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 8000
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "url": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uri"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "kind",
                "title"
              ]
            }
          },
          "update": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1
                },
                "title": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "body": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 8000
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "url": {
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uri"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id"
              ]
            }
          },
          "remove": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          },
          "brandTerms": {
            "description": "Replaces the brand terms: what people type when already looking for this business (its name, products, misspellings). Search Console splits branded from non-branded queries with them. [] goes back to the client's name and domain.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DraftClientBriefInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListWrittenReportsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetWrittenReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "SaveWrittenReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "markdown": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200000
          },
          "templateId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "title",
          "markdown"
        ],
        "additionalProperties": false
      },
      "DeleteWrittenReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "SetReportSharingInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          },
          "shared": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "reportId",
          "shared"
        ],
        "additionalProperties": false
      },
      "ListReportTemplatesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "SaveReportTemplateInput": {
        "type": "object",
        "properties": {
          "templateId": {
            "type": "string",
            "minLength": 1
          },
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "audience": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "sections": {
            "minItems": 1,
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "heading": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "guidance": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 2000
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "heading"
              ]
            }
          },
          "tone": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "signOff": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "sections"
        ],
        "additionalProperties": false
      },
      "DeleteReportTemplateInput": {
        "type": "object",
        "properties": {
          "templateId": {
            "type": "string",
            "minLength": 1
          },
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "templateId"
        ],
        "additionalProperties": false
      },
      "GetGa4OverviewInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "channel": {
            "default": "organic",
            "description": "organic: Organic Search; ai: sessions sent by AI assistants (ChatGPT, Perplexity, Gemini, Copilot, Claude and others, read from the session source); all: every channel.",
            "type": "string",
            "enum": [
              "organic",
              "all",
              "ai"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4TrafficAcquisitionInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "groupBy": {
            "default": "channel",
            "description": "aiSource: the source / medium of AI assistants' sessions only.",
            "type": "string",
            "enum": [
              "channel",
              "sourceMedium",
              "campaign",
              "aiSource"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4LandingPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "channel": {
            "default": "organic",
            "description": "organic: Organic Search; ai: sessions sent by AI assistants (ChatGPT, Perplexity, Gemini, Copilot, Claude and others, read from the session source); all: every channel.",
            "type": "string",
            "enum": [
              "organic",
              "all",
              "ai"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4PagePerformanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "channel": {
            "default": "organic",
            "description": "organic: Organic Search; ai: sessions sent by AI assistants (ChatGPT, Perplexity, Gemini, Copilot, Claude and others, read from the session source); all: every channel.",
            "type": "string",
            "enum": [
              "organic",
              "all",
              "ai"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4KeyEventsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "by": {
            "default": "event",
            "type": "string",
            "enum": [
              "event",
              "landingPage"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4EcommerceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "by": {
            "default": "item",
            "type": "string",
            "enum": [
              "item",
              "landingPage"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4SiteSearchInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4AudienceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          },
          "by": {
            "default": "device",
            "type": "string",
            "enum": [
              "device",
              "country",
              "newVsReturning"
            ]
          },
          "channel": {
            "default": "organic",
            "description": "organic: Organic Search; ai: sessions sent by AI assistants (ChatGPT, Perplexity, Gemini, Copilot, Claude and others, read from the session source); all: every channel.",
            "type": "string",
            "enum": [
              "organic",
              "all",
              "ai"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGa4MeasurementHealthInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSearchOpportunitiesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetWebAnalyticsSetupInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCollectContractInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "SetUpWebAnalyticsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "hostnames": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            }
          },
          "excludePaths": {
            "description": "Paths never recorded, enforced on the server whatever the snippet says: [\"/app/*\", \"/verify\", \"/reset\"]. \"*\" matches anything. Replaces the list; [] clears it.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "includePaths": {
            "description": "When set, only pageviews on these paths are recorded: [\"/\", \"/blog/*\"]. A custom event elsewhere (a sign-up that lands in the app) still counts, stored without its path. [] clears it.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "pathTemplates": {
            "description": "Paths stored under a template when they fit, so names and ids in a path are never stored and their pages count together: [\"/:username/:slug\"] stores /ada/intro-call as /:username/:slug. A \":name\" segment matches any one segment; when several fit, the one with the most fixed segments wins. Applied after excludePaths. Replaces the list; [] clears it.",
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200,
              "pattern": "^\\/"
            }
          },
          "partners": {
            "description": "Third parties serving pages on this site (a docs, blog or forum host) under the same site key. Their events send p: {source: \"<name>\"}, are kept only on their paths (others are dropped as excluded_by_partner_paths) and are reported with get_web_analytics_breakdown {breakdown: \"partners\"}: [{name: \"forumulate\", paths: [\"/docs/*\", \"/blog/*\"]}]. Replaces the list; [] clears it.",
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "pattern": "^[a-z0-9_-]{1,40}$"
                },
                "paths": {
                  "minItems": 1,
                  "maxItems": 50,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                }
              },
              "required": [
                "name",
                "paths"
              ]
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetWebAnalyticsSummaryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "description": "The period: the last 7, 30 or 90 days, today included.",
            "anyOf": [
              {
                "type": "number",
                "const": 7
              },
              {
                "type": "number",
                "const": 30
              },
              {
                "type": "number",
                "const": 90
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetWebAnalyticsBreakdownInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "breakdown": {
            "type": "string",
            "enum": [
              "pages",
              "entry_pages",
              "exit_pages",
              "sources",
              "referrers",
              "campaigns",
              "countries",
              "devices",
              "browsers",
              "os",
              "events",
              "channels",
              "ai_sources",
              "ai_landing_pages",
              "partners"
            ]
          },
          "days": {
            "default": 30,
            "description": "The period: the last 7, 30 or 90 days, today included.",
            "anyOf": [
              {
                "type": "number",
                "const": 7
              },
              {
                "type": "number",
                "const": 30
              },
              {
                "type": "number",
                "const": 90
              }
            ]
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId",
          "breakdown"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilitySetupInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SaveAiVisibilitySetupInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "addPrompts": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "text": {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 500
                },
                "market": {
                  "anyOf": [
                    {
                      "type": "string",
                      "pattern": "^[a-zA-Z]{2}$"
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "topic": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 80
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "branded": {
                  "anyOf": [
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "text"
              ]
            }
          },
          "updatePrompts": {
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "minLength": 1
                },
                "topic": {
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 80
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "branded": {
                  "anyOf": [
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "id"
              ]
            }
          },
          "retirePromptIds": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "addBrands": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 120
                },
                "domain": {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 253
                },
                "aliases": {
                  "maxItems": 10,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  }
                },
                "isClient": {
                  "type": "boolean"
                }
              },
              "required": [
                "name",
                "domain"
              ]
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SetAiVisibilityScheduleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "cadence": {
            "type": "string",
            "enum": [
              "off",
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "engines": {
            "anyOf": [
              {
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "claude",
                    "chatgpt",
                    "gemini",
                    "perplexity",
                    "google-aio",
                    "copilot",
                    "google-ai-mode",
                    "grok",
                    "meta-ai",
                    "deepseek"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "sentiment": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "EstimateAiVisibilityCostInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RunAiVisibilityCheckInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilityRunsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilityResultsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "capturedAt": {
            "type": "string",
            "minLength": 10
          },
          "topic": {
            "description": "Only questions in this topic.",
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "segment": {
            "description": "neutral: only questions naming no tracked brand (who gets recommended unprompted); branded: only those naming one.",
            "type": "string",
            "enum": [
              "branded",
              "neutral"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilityAnswerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "promptId": {
            "type": "string",
            "minLength": 1
          },
          "model": {
            "type": "string",
            "enum": [
              "claude",
              "chatgpt",
              "gemini",
              "perplexity",
              "google-aio",
              "copilot",
              "google-ai-mode",
              "grok",
              "meta-ai",
              "deepseek"
            ]
          },
          "capturedAt": {
            "type": "string",
            "minLength": 10
          }
        },
        "required": [
          "clientId",
          "promptId",
          "model",
          "capturedAt"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilityTrendInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 7,
            "maximum": 180
          },
          "topic": {
            "description": "Only questions in this topic.",
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "segment": {
            "description": "neutral: only questions naming no tracked brand (who gets recommended unprompted); branded: only those naming one.",
            "type": "string",
            "enum": [
              "branded",
              "neutral"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ExportAiVisibilityDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "include": {
            "default": "mentions",
            "type": "string",
            "enum": [
              "mentions",
              "answers"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ExploreAiPromptInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "prompt": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2000
          },
          "engines": {
            "default": [
              "claude"
            ],
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "claude",
                "chatgpt",
                "gemini",
                "perplexity",
                "google-aio",
                "copilot",
                "google-ai-mode",
                "grok",
                "meta-ai",
                "deepseek"
              ]
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "prompt"
        ],
        "additionalProperties": false
      },
      "SuggestAiPromptsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "topic": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200
          },
          "count": {
            "default": 12,
            "type": "integer",
            "minimum": 3,
            "maximum": 40
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiCitedSourcesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "engine": {
            "type": "string",
            "enum": [
              "claude",
              "chatgpt",
              "gemini",
              "perplexity",
              "google-aio",
              "copilot",
              "google-ai-mode",
              "grok",
              "meta-ai",
              "deepseek"
            ]
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "topic": {
            "description": "Only questions in this topic.",
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "segment": {
            "description": "neutral: only questions naming no tracked brand (who gets recommended unprompted); branded: only those naming one.",
            "type": "string",
            "enum": [
              "branded",
              "neutral"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiVisibilitySentimentInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "topic": {
            "description": "Only questions in this topic.",
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "segment": {
            "description": "neutral: only questions naming no tracked brand (who gets recommended unprompted); branded: only those naming one.",
            "type": "string",
            "enum": [
              "branded",
              "neutral"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AssessAiVisibilitySentimentInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "capturedAt": {
            "type": "string",
            "minLength": 10
          },
          "maxAnswers": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "rejudge": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListMarketsInput": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "maxLength": 80
          }
        },
        "additionalProperties": false
      },
      "GetLiveSerpsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": 2000,
            "maximum": 2999
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "engine": {
            "default": "google",
            "type": "string",
            "enum": [
              "google",
              "bing",
              "youtube",
              "amazon",
              "yandex",
              "baidu",
              "naver",
              "duckduckgo",
              "yahoo",
              "seznam",
              "app_store",
              "google_play"
            ]
          },
          "device": {
            "default": "desktop",
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          },
          "top": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "FindSerpCompetitorsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "minimum": 2000,
            "maximum": 2999
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "limit": {
            "default": 15,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "exclude": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "PinTrackedKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "pinned": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "keywordIds"
        ],
        "additionalProperties": false
      },
      "GetKeywordListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "listId"
        ],
        "additionalProperties": false
      },
      "SetKeywordNotesInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "notes": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "keywordId": {
                  "type": "string",
                  "minLength": 1
                },
                "note": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 2000
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "keywordId",
                "note"
              ]
            }
          }
        },
        "required": [
          "listId",
          "notes"
        ],
        "additionalProperties": false
      },
      "WhoamiInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "GetLowCtrQueriesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "minImpressions": {
            "default": 200,
            "type": "integer",
            "minimum": 50,
            "maximum": 9007199254740991
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetOpportunitiesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetClientInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateClientInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "monthlyBudgetUsd": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "name",
          "domain"
        ],
        "additionalProperties": false
      },
      "UpdateClientInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "monthlyBudgetUsd": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ArchiveClientInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RestoreClientInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListProjectsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateProjectInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "locationCode": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991,
            "description": "A DataForSEO location: a country, or a region, county or city (find one with search_locations)."
          },
          "languageCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          }
        },
        "required": [
          "clientId",
          "name"
        ],
        "additionalProperties": false
      },
      "GetSiteStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListRankTrackersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateRankTrackerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "projectId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "engine": {
            "default": "google",
            "type": "string",
            "enum": [
              "google",
              "bing",
              "youtube",
              "amazon",
              "app_store",
              "yandex",
              "baidu",
              "naver",
              "duckduckgo",
              "yahoo",
              "seznam",
              "google_play"
            ]
          },
          "device": {
            "default": "desktop",
            "type": "string",
            "enum": [
              "desktop",
              "mobile",
              "both"
            ]
          },
          "frequency": {
            "default": "weekly",
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "manual"
            ]
          },
          "locationCode": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991,
            "description": "A DataForSEO location: a country, or a region, county or city (find one with search_locations)."
          },
          "languageCode": {
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "runHour": {
            "description": "The UTC hour scheduled runs happen at (default 3).",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 23
              },
              {
                "type": "null"
              }
            ]
          },
          "runDay": {
            "description": "Weekly: the weekday, 0 Sunday – 6 Saturday. Monthly: the day of the month, 1–28.",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 28
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "description": "Results read per keyword (default 100). Deeper costs more per check.",
            "type": "integer",
            "minimum": 10,
            "maximum": 200
          },
          "match": {
            "description": "domain: the exact host; subdomains: it and every subdomain; prefix: only addresses under urlPrefix (a folder or one page).",
            "type": "string",
            "enum": [
              "domain",
              "subdomains",
              "prefix"
            ]
          },
          "urlPrefix": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 4,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "name"
        ],
        "additionalProperties": false
      },
      "UpdateRankTrackerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "device": {
            "type": "string",
            "enum": [
              "desktop",
              "mobile",
              "both"
            ]
          },
          "frequency": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "manual"
            ]
          },
          "runHour": {
            "description": "The UTC hour scheduled runs happen at (default 3).",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 23
              },
              {
                "type": "null"
              }
            ]
          },
          "runDay": {
            "description": "Weekly: the weekday, 0 Sunday – 6 Saturday. Monthly: the day of the month, 1–28.",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 28
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "description": "Results read per keyword (default 100). Deeper costs more per check.",
            "type": "integer",
            "minimum": 10,
            "maximum": 200
          },
          "match": {
            "description": "domain: the exact host; subdomains: it and every subdomain; prefix: only addresses under urlPrefix (a folder or one page).",
            "type": "string",
            "enum": [
              "domain",
              "subdomains",
              "prefix"
            ]
          },
          "urlPrefix": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 4,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "DeleteRankTrackerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "ListTrackedKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "AddTrackedKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "terms": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "terms"
        ],
        "additionalProperties": false
      },
      "RemoveTrackedKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "terms": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "terms"
        ],
        "additionalProperties": false
      },
      "StartCrawlInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCrawlStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "crawlId"
        ],
        "additionalProperties": false
      },
      "ListCrawlsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListCrawlIssuesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          },
          "indexableOnly": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListReportsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "sections": {
            "minItems": 1,
            "maxItems": 8,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "rank-summary",
                "share-of-voice",
                "keyword-movers",
                "backlink-summary",
                "traffic",
                "core-web-vitals",
                "site-health",
                "audit-summary"
              ]
            }
          }
        },
        "required": [
          "clientId",
          "title",
          "sections"
        ],
        "additionalProperties": false
      },
      "SendReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          },
          "idempotencyKey": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "ListAlertRulesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateAlertRuleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "type": "string",
            "enum": [
              "rank-drop",
              "traffic-drop",
              "new-critical-issues",
              "backlinks-lost",
              "site-unreachable",
              "serp-features",
              "competitor-new-pages",
              "page-changes",
              "ai-mention-drop",
              "competitor-new-keywords",
              "web-mentions",
              "link-velocity"
            ]
          },
          "threshold": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "cooldownHours": {
            "type": "integer",
            "minimum": 0,
            "maximum": 720
          },
          "webhookUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "channel": {
            "type": "string",
            "enum": [
              "slack",
              "webhook",
              "discord",
              "email",
              "telegram"
            ]
          },
          "emailRecipients": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            }
          },
          "telegramChatId": {
            "type": "string",
            "minLength": 2,
            "maxLength": 64
          },
          "paidSource": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "kind",
          "threshold"
        ],
        "additionalProperties": false
      },
      "UpdateAlertRuleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "type": "string",
            "minLength": 1
          },
          "threshold": {
            "type": "integer",
            "minimum": 1,
            "maximum": 9007199254740991
          },
          "cooldownHours": {
            "type": "integer",
            "minimum": 0,
            "maximum": 720
          },
          "webhookUrl": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "channel": {
            "type": "string",
            "enum": [
              "slack",
              "webhook",
              "discord",
              "email",
              "telegram"
            ]
          },
          "emailRecipients": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            }
          },
          "telegramChatId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ]
          },
          "paused": {
            "type": "boolean"
          },
          "paidSource": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "ruleId"
        ],
        "additionalProperties": false
      },
      "DeleteAlertRuleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "ruleId"
        ],
        "additionalProperties": false
      },
      "TestAlertRuleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "ruleId"
        ],
        "additionalProperties": false
      },
      "GetVendorConnectionsInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "GetClientIntegrationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCostsInput": {
        "type": "object",
        "properties": {
          "sinceDays": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          }
        },
        "additionalProperties": false
      },
      "GetClientCostsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sinceDays": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListApiKeysInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "CreateApiKeyInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "clientId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "role": {
            "default": "manager",
            "type": "string",
            "enum": [
              "client_viewer",
              "analyst",
              "manager",
              "site_admin",
              "admin"
            ]
          },
          "expiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          },
          "maxCostUsdPerCall": {
            "description": "The most any one call with this key may spend, in USD. Calls asking for more are capped to it.",
            "type": "number",
            "minimum": 0,
            "maximum": 1000
          },
          "mode": {
            "default": "live",
            "description": "test mints a sandbox key: it acts in the agency's sandbox, with sample clients and DataForSEO's documented answers at $0, no model calls, and no reach into live clients — for building and testing an integration without spending.",
            "type": "string",
            "enum": [
              "live",
              "test"
            ]
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "RevokeApiKeyInput": {
        "type": "object",
        "properties": {
          "keyId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "keyId"
        ],
        "additionalProperties": false
      },
      "ListApiActivityInput": {
        "type": "object",
        "properties": {
          "sinceHours": {
            "default": 24,
            "type": "integer",
            "minimum": 1,
            "maximum": 2160
          },
          "keyId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "additionalProperties": false
      },
      "ListTeamMembersInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "AddTeamMemberInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "manager",
              "analyst",
              "client_viewer"
            ]
          },
          "clientIds": {
            "default": [],
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "email",
          "role"
        ],
        "additionalProperties": false
      },
      "RemoveTeamMemberInput": {
        "type": "object",
        "properties": {
          "membershipId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "membershipId"
        ],
        "additionalProperties": false
      },
      "SaveVendorCredentialInput": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "dataforseo",
              "serpapi",
              "anthropic",
              "bingwebmaster",
              "reportwebhook",
              "serpproxy",
              "googleads",
              "crux",
              "chatgpt",
              "gemini",
              "perplexity",
              "grok",
              "meta-ai",
              "deepseek",
              "pagespeed",
              "telegram",
              "naversearchad",
              "knowledgegraph",
              "webrisk"
            ]
          },
          "login": {
            "type": "string",
            "maxLength": 200
          },
          "secret": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20000
          },
          "googleAds": {
            "type": "object",
            "properties": {
              "developerToken": {
                "type": "string",
                "minLength": 1
              },
              "customerId": {
                "type": "string",
                "minLength": 1
              },
              "loginCustomerId": {
                "type": "string"
              },
              "clientId": {
                "type": "string",
                "minLength": 1
              },
              "clientSecret": {
                "type": "string",
                "minLength": 1
              },
              "refreshToken": {
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "developerToken",
              "customerId",
              "clientId",
              "clientSecret",
              "refreshToken"
            ]
          }
        },
        "required": [
          "provider",
          "secret"
        ],
        "additionalProperties": false
      },
      "RemoveVendorCredentialInput": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "dataforseo",
              "serpapi",
              "anthropic",
              "bingwebmaster",
              "reportwebhook",
              "serpproxy",
              "googleads",
              "crux",
              "chatgpt",
              "gemini",
              "perplexity",
              "grok",
              "meta-ai",
              "deepseek",
              "pagespeed",
              "telegram",
              "naversearchad",
              "knowledgegraph",
              "webrisk"
            ]
          }
        },
        "required": [
          "provider"
        ],
        "additionalProperties": false
      },
      "GetBrandingInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "SetBrandingInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "logoUrl": {
            "type": "string",
            "maxLength": 2048
          },
          "primaryColor": {
            "type": "string",
            "maxLength": 7
          }
        },
        "required": [
          "name",
          "logoUrl",
          "primaryColor"
        ],
        "additionalProperties": false
      },
      "ListConnectedAppsInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "DisconnectAppInput": {
        "type": "object",
        "properties": {
          "grantId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "grantId"
        ],
        "additionalProperties": false
      },
      "GetBillingInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "GetBillingLinkInput": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string",
            "enum": [
              "studio",
              "agency",
              "network"
            ]
          }
        },
        "additionalProperties": false
      },
      "ListLocalLocationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AddLocalLocationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "placeId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "cid": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{5,25}$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "name",
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "GetLocalVisibilityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "term": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "clientId",
          "locationId",
          "term"
        ],
        "additionalProperties": false
      },
      "RunLocalGridScanInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "term": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "size": {
            "default": 5,
            "description": "Grid width in points: 3, 5, 7, 9 or 13.",
            "anyOf": [
              {
                "type": "number",
                "const": 3
              },
              {
                "type": "number",
                "const": 5
              },
              {
                "type": "number",
                "const": 7
              },
              {
                "type": "number",
                "const": 9
              },
              {
                "type": "number",
                "const": 13
              }
            ]
          },
          "spacingKm": {
            "default": 1.5,
            "type": "number",
            "minimum": 0.1,
            "maximum": 25
          },
          "device": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "desktop",
                  "mobile"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "moreTerms": {
            "default": [],
            "maxItems": 2,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "locationId",
          "term"
        ],
        "additionalProperties": false
      },
      "SyncLocalReviewsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "locationId"
        ],
        "additionalProperties": false
      },
      "GetLocalSeoAuditInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "useListing": {
            "default": true,
            "type": "boolean"
          },
          "postsTaskId": {
            "default": null,
            "description": "A get_business_posts taskId for this listing; collecting it is free.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ]
          },
          "competitorRadiusKm": {
            "default": 5,
            "description": "Radius for competitor density; 0 skips the paid business search.",
            "type": "number",
            "minimum": 0,
            "maximum": 50
          },
          "directories": {
            "default": false,
            "type": "boolean"
          },
          "duplicates": {
            "default": false,
            "description": "Search the listings within 1 km for duplicates at this address or phone (one paid business search).",
            "type": "boolean"
          },
          "city": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "service": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "model": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "storefront",
              "sab",
              "hybrid"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "locationId"
        ],
        "additionalProperties": false
      },
      "GetBacklinkAuditInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "moneyTerms": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBacklinkHealthInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "moneyTerms": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "spamScores": {
            "default": {},
            "description": "Domain → DataForSEO spam score, from get_backlink_spam_scores.",
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            }
          },
          "fetchSpamScores": {
            "default": false,
            "description": "True to buy the vendor's spam score for every linking site inside this call (one paid request of up to 1,000 sites, the price of get_backlink_spam_scores; sites scored in the last 30 days are reused free). Quote it with estimate_cost or dryRun first.",
            "type": "boolean"
          },
          "industry": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "saas",
                  "ecommerce",
                  "local",
                  "publisher",
                  "agency"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetLinkChecksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RecheckLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "render": {
            "default": false,
            "description": "True to read the unverifiable_js pages (or sourceUrls) in a real browser, up to 25.",
            "type": "boolean"
          },
          "sourceUrls": {
            "description": "With render: the linking pages to read, from get_link_checks. Default: those marked unverifiable_js.",
            "maxItems": 25,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBacklinkSpamScoresInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domains": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "domains"
        ],
        "additionalProperties": false
      },
      "ListLinkProspectsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AddLinkProspectsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "prospects": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sourceDomain": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 253
                },
                "reason": {
                  "type": "string",
                  "maxLength": 500
                },
                "targetUrl": {
                  "description": "The one page to act on (a dead page, a thread, an article); omit for the whole site.",
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 2000,
                      "format": "uri"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "sourceDomain"
              ]
            }
          }
        },
        "required": [
          "clientId",
          "prospects"
        ],
        "additionalProperties": false
      },
      "SetLinkProspectStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "prospectId": {
            "type": "string",
            "minLength": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "identified",
              "contacted",
              "replied",
              "won",
              "rejected"
            ]
          },
          "linkUrl": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "contactEmail": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 320,
                "format": "email",
                "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "prospectId",
          "status"
        ],
        "additionalProperties": false
      },
      "AnalyseServerLogInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "contents": {
            "type": "string",
            "minLength": 1,
            "maxLength": 67108864
          }
        },
        "required": [
          "clientId",
          "contents"
        ],
        "additionalProperties": false
      },
      "ListReportSchedulesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ScheduleReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          },
          "cadence": {
            "default": "monthly",
            "type": "string",
            "enum": [
              "monthly",
              "weekly"
            ]
          },
          "recipients": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            },
            "description": "Email addresses the report goes to. At least one."
          }
        },
        "required": [
          "clientId",
          "reportId",
          "recipients"
        ],
        "additionalProperties": false
      },
      "UpdateReportScheduleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "scheduleId": {
            "type": "string",
            "minLength": 1
          },
          "cadence": {
            "type": "string",
            "enum": [
              "monthly",
              "weekly"
            ]
          },
          "recipients": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            },
            "description": "Email addresses the report goes to. At least one."
          },
          "paused": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "scheduleId"
        ],
        "additionalProperties": false
      },
      "DeleteReportScheduleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "scheduleId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "scheduleId"
        ],
        "additionalProperties": false
      },
      "ArchiveReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "AddCompetitorsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "domains": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            },
            "description": "Domains such as example.com. A URL is reduced to its domain."
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "domains"
        ],
        "additionalProperties": false
      },
      "RemoveCompetitorsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "domains": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            },
            "description": "Domains such as example.com. A URL is reduced to its domain."
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "domains"
        ],
        "additionalProperties": false
      },
      "GetConnectionLinkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "service": {
            "type": "string",
            "enum": [
              "search_console",
              "search_console_sitemaps",
              "google_analytics",
              "yandex_webmaster",
              "google_business_profile"
            ]
          },
          "propertyUrl": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          },
          "ga4PropertyId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "service"
        ],
        "additionalProperties": false
      },
      "GetGoogleServiceAccountInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "ConnectSearchConsoleServiceAccountInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "propertyUrl": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ConnectGoogleAnalyticsServiceAccountInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "propertyId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 32
          }
        },
        "required": [
          "clientId",
          "propertyId"
        ],
        "additionalProperties": false
      },
      "ConnectYandexWithTokenInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "token": {
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          }
        },
        "required": [
          "clientId",
          "token"
        ],
        "additionalProperties": false
      },
      "ListPortalLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreatePortalLinkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80,
            "description": "Who the link is for, so it can be told apart and revoked later"
          }
        },
        "required": [
          "clientId",
          "label"
        ],
        "additionalProperties": false
      },
      "RevokePortalLinkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "linkId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "linkId"
        ],
        "additionalProperties": false
      },
      "OnboardSiteInput": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "framework": {
            "type": "string",
            "enum": [
              "nextjs",
              "astro",
              "remix",
              "sveltekit",
              "nuxt",
              "html",
              "wordpress",
              "other"
            ]
          },
          "keywords": {
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "verification": {
            "default": "file",
            "description": "file (a page at the site root, the default), meta (a tag in the <head>) or dns (a TXT record, which also covers every subdomain and protocol).",
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          },
          "healthKey": {
            "description": "Also make a read-only key pinned to this client that can spend nothing, for seolyticize doctor. It is shown once in healthKey.key; a later call keeps it and returns its id alone.",
            "type": "boolean"
          },
          "trackerFrequency": {
            "description": "How often the client's rank tracker runs once it has keywords: weekly is the default for a new tracker. Applied to an existing client's trackers too. update_rank_tracker changes it later.",
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "manual"
            ]
          }
        },
        "required": [
          "domain"
        ],
        "additionalProperties": false
      },
      "ApplyManifestInput": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "framework": {
            "type": "string",
            "enum": [
              "nextjs",
              "astro",
              "remix",
              "sveltekit",
              "nuxt",
              "html",
              "wordpress",
              "other"
            ]
          },
          "verification": {
            "default": "file",
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          },
          "trackerFrequency": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "manual"
            ]
          },
          "monthlyBudgetUsd": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 1000000
              },
              {
                "type": "null"
              }
            ]
          },
          "budgetAlertAt": {
            "description": "The share of the budget that alerts (0.8 = 80%). Left as it is when omitted.",
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0,
                "maximum": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "domainSweep": {
            "type": "boolean"
          },
          "deployHook": {
            "default": false,
            "type": "boolean"
          },
          "healthKey": {
            "description": "Also make the read-only key for seolyticize doctor, as onboard_site does; shown once at the top of the answer as healthKey.key, and kept on later runs.",
            "type": "boolean"
          },
          "brief": {
            "type": "object",
            "properties": {
              "overview": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 4000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "goal": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 4000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "positioning": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 4000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "audience": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 4000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "voice": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 4000
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "brandTerms": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                }
              },
              "add": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "kind": {
                      "type": "string",
                      "enum": [
                        "competitor",
                        "key_page",
                        "section",
                        "research"
                      ]
                    },
                    "title": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    "body": {
                      "anyOf": [
                        {
                          "type": "string",
                          "maxLength": 8000
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "url": {
                      "anyOf": [
                        {
                          "type": "string",
                          "format": "uri"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "required": [
                    "kind",
                    "title"
                  ]
                }
              }
            }
          },
          "analytics": {
            "description": "set_up_web_analytics arguments; each list replaces the one there.",
            "type": "object",
            "properties": {
              "hostnames": {
                "minItems": 1,
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 253
                }
              },
              "includePaths": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "excludePaths": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              "pathTemplates": {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 200
                }
              },
              "partners": {
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 40
                    },
                    "paths": {
                      "minItems": 1,
                      "maxItems": 50,
                      "type": "array",
                      "items": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      }
                    }
                  },
                  "required": [
                    "name",
                    "paths"
                  ]
                }
              }
            }
          },
          "crawl": {
            "description": "set_crawl_settings arguments without clientId, such as {render: \"shells\", stripParams: [\"ref\"]}; checked by that tool.",
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "alerts": {
            "description": "add_default_alerts arguments: the default alerts, sent here.",
            "type": "object",
            "properties": {
              "channel": {
                "type": "string",
                "enum": [
                  "slack",
                  "webhook",
                  "discord",
                  "email",
                  "telegram"
                ]
              },
              "webhookUrl": {
                "type": "string",
                "maxLength": 2048,
                "format": "uri"
              },
              "emailRecipients": {
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "email",
                  "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                }
              },
              "telegramChatId": {
                "type": "string",
                "minLength": 2,
                "maxLength": 64
              },
              "include": {
                "maxItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "page-changes"
                  ]
                }
              }
            }
          },
          "facts": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 120
                },
                "value": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500
                },
                "category": {
                  "default": "other",
                  "type": "string",
                  "enum": [
                    "price",
                    "limit",
                    "country",
                    "date",
                    "contact",
                    "other"
                  ]
                },
                "terms": {
                  "default": [],
                  "maxItems": 10,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 60
                  }
                },
                "sourceUrl": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uri"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "key",
                "value"
              ]
            }
          },
          "goals": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "pageview",
                    "event"
                  ]
                },
                "match": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "valueMinor": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 9007199254740991
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "name",
                "kind",
                "match"
              ]
            }
          },
          "funnels": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "steps": {
                  "minItems": 2,
                  "maxItems": 8,
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "pageview",
                          "event"
                        ]
                      },
                      "match": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "label": {
                        "type": "string",
                        "maxLength": 100
                      }
                    },
                    "required": [
                      "kind",
                      "match"
                    ]
                  }
                }
              },
              "required": [
                "name",
                "steps"
              ]
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "domain"
        ],
        "additionalProperties": false
      },
      "MoveSiteInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "newDomain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "verification": {
            "default": "file",
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          },
          "overlapDays": {
            "default": 30,
            "description": "How long events from the old hostnames are still accepted.",
            "type": "integer",
            "minimum": 0,
            "maximum": 365
          }
        },
        "required": [
          "clientId",
          "newDomain"
        ],
        "additionalProperties": false
      },
      "VerifySiteInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetNextStepsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "BootstrapKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seeds": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "competitorDomains": {
            "default": [],
            "maxItems": 3,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "IssueSiteVerificationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "method": {
            "default": "file",
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          },
          "siteUrl": {
            "description": "A URL-prefix site other than https://<domain>/, such as https://www.example.com/. Not used for dns.",
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "VerifySiteOwnershipInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "method": {
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          },
          "siteUrl": {
            "description": "A URL-prefix site other than https://<domain>/, such as https://www.example.com/. Not used for dns.",
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "addOwners": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateInviteCodeInput": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "maxUses": {
            "default": 1,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "expiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "keyExpiresInDays": {
            "type": "integer",
            "minimum": 1,
            "maximum": 3650
          },
          "keyMaxCostUsdPerCall": {
            "type": "number",
            "minimum": 0,
            "maximum": 1000
          }
        },
        "required": [
          "label"
        ],
        "additionalProperties": false
      },
      "ListInviteCodesInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "RevokeInviteCodeInput": {
        "type": "object",
        "properties": {
          "inviteCodeId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "inviteCodeId"
        ],
        "additionalProperties": false
      },
      "CreateDeployHookInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sitemapUrl": {
            "description": "Read this sitemap instead of robots.txt's Sitemap: line or /sitemap.xml.",
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "sitemaps": {
            "description": "Sitemaps to read as well as the site's own, on any host (a CMS elsewhere). Every call diffs each one and the reply gives bySitemap: its pages and how many changed.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2048,
              "format": "uri"
            }
          },
          "pathUrl": {
            "description": "false: leave webhookUrl, the secret in a path, out of the answer.",
            "type": "boolean"
          },
          "ifMissing": {
            "default": false,
            "description": "Leave an existing hook alone instead of refusing with hook_exists.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RotateDeployHookInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sitemapUrl": {
            "description": "Read this sitemap from now on.",
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "sitemaps": {
            "description": "Sitemaps to read as well as the site's own, on any host (a CMS elsewhere). Every call diffs each one and the reply gives bySitemap: its pages and how many changed.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2048,
              "format": "uri"
            }
          },
          "pathUrl": {
            "description": "false: leave webhookUrl, the secret in a path, out of the answer.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetDeployHookInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RevokeDeployHookInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RefreshRankingsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RefreshDomainDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetRunStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "job": {
            "type": "string",
            "enum": [
              "rank",
              "domain",
              "links"
            ]
          },
          "runId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "clientId",
          "job",
          "runId"
        ],
        "additionalProperties": false
      },
      "GetBrandMentionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1,
            "description": "The client whose account and monthly cap pay for the lookup"
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetKeywordTrendsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1,
            "description": "The client whose account and monthly cap pay for the lookup"
          },
          "terms": {
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "terms"
        ],
        "additionalProperties": false
      },
      "EstimateDomainTrafficInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1,
            "description": "The client whose account and monthly cap pay for the lookup"
          },
          "targets": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 253
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "targets"
        ],
        "additionalProperties": false
      },
      "GetSubdomainTrafficInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1,
            "description": "The client whose account and monthly cap pay for the lookup"
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "domain"
        ],
        "additionalProperties": false
      },
      "GetDomainTechnologiesInput": {
        "type": "object",
        "properties": {
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253
          }
        },
        "required": [
          "domain"
        ],
        "additionalProperties": false
      },
      "RenameKeywordListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          }
        },
        "required": [
          "listId",
          "name"
        ],
        "additionalProperties": false
      },
      "DeleteKeywordListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "listId"
        ],
        "additionalProperties": false
      },
      "AddListToTrackerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "listId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId",
          "listId"
        ],
        "additionalProperties": false
      },
      "QueryKeywordListInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "text": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "tags": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40
            }
          },
          "untagged": {
            "default": false,
            "type": "boolean"
          },
          "intents": {
            "default": [],
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "informational",
                "navigational",
                "commercial",
                "transactional"
              ]
            }
          },
          "minVolume": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "maxVolume": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "minDifficulty": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "maxDifficulty": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "sort": {
            "default": "added",
            "type": "string",
            "enum": [
              "term",
              "volume",
              "difficulty",
              "cpc",
              "added",
              "refreshed"
            ]
          },
          "order": {
            "default": null,
            "description": "Default: A to Z for term, oldest first for added, biggest first otherwise.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "asc",
                  "desc"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 500,
            "type": "integer",
            "minimum": 1,
            "maximum": 5000
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "format": {
            "default": "json",
            "type": "string",
            "enum": [
              "json",
              "csv"
            ]
          }
        },
        "required": [
          "listId"
        ],
        "additionalProperties": false
      },
      "TagListKeywordsInput": {
        "type": "object",
        "properties": {
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "keywordIds": {
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 5000,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              {
                "type": "string",
                "const": "all"
              }
            ]
          },
          "tags": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 40
            }
          },
          "remove": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "listId",
          "keywordIds",
          "tags"
        ],
        "additionalProperties": false
      },
      "RefreshKeywordListMetricsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "listId": {
            "type": "string",
            "minLength": 1
          },
          "onlyOlderThanDays": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 365
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "listId"
        ],
        "additionalProperties": false
      },
      "GetSearchChangesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Length of each period, ending on the newest day Google has finished counting.",
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          },
          "compare": {
            "default": "previous",
            "description": "previous: the same number of days just before. year: the same days a year earlier.",
            "type": "string",
            "enum": [
              "previous",
              "year"
            ]
          },
          "searchType": {
            "default": "web",
            "description": "Search Console's search type: web (default), image, video, news, discover or googleNews. Discover and Google News report pages but no queries.",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "dimension": {
            "default": "query",
            "type": "string",
            "enum": [
              "query",
              "page"
            ]
          },
          "brand": {
            "default": "all",
            "description": "non_branded is what SEO work moves; branded is people already looking for the client.",
            "type": "string",
            "enum": [
              "all",
              "branded",
              "non_branded"
            ]
          },
          "country": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z]{3}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "device": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "DESKTOP",
                  "MOBILE",
                  "TABLET"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "minImpressions": {
            "default": 10,
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBrandSplitInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "searchType": {
            "default": "web",
            "description": "Search Console's search type: web (default), image, video, news, discover or googleNews. Discover and Google News report pages but no queries.",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "from": {
            "default": null,
            "description": "Default: 16 months before to.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "description": "Default: the newest day archived.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "interval": {
            "default": "week",
            "type": "string",
            "enum": [
              "day",
              "week",
              "month"
            ]
          },
          "country": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z]{3}$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetQueryPageSwapsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Length of each period, ending on the newest day Google has finished counting.",
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          },
          "compare": {
            "default": "previous",
            "description": "previous: the same number of days just before. year: the same days a year earlier.",
            "type": "string",
            "enum": [
              "previous",
              "year"
            ]
          },
          "searchType": {
            "default": "web",
            "description": "Search Console's search type: web (default), image, video, news, discover or googleNews. Discover and Google News report pages but no queries.",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "brand": {
            "default": "all",
            "description": "non_branded is what SEO work moves; branded is people already looking for the client.",
            "type": "string",
            "enum": [
              "all",
              "branded",
              "non_branded"
            ]
          },
          "minImpressions": {
            "default": 20,
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetContentGroupsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Length of each period, ending on the newest day Google has finished counting.",
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          },
          "compare": {
            "default": "previous",
            "description": "previous: the same number of days just before. year: the same days a year earlier.",
            "type": "string",
            "enum": [
              "previous",
              "year"
            ]
          },
          "searchType": {
            "default": "web",
            "description": "Search Console's search type: web (default), image, video, news, discover or googleNews. Discover and Google News report pages but no queries.",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "groups": {
            "default": null,
            "anyOf": [
              {
                "maxItems": 50,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 80
                    },
                    "pattern": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200,
                      "description": "A path glob: /guides/*, /community/*/u, /"
                    }
                  },
                  "required": [
                    "name",
                    "pattern"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "country": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-z]{3}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "device": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "DESKTOP",
                  "MOBILE",
                  "TABLET"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSearchAppearanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Length of each period, ending on the newest day Google has finished counting.",
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          },
          "compare": {
            "default": "previous",
            "description": "previous: the same number of days just before. year: the same days a year earlier.",
            "type": "string",
            "enum": [
              "previous",
              "year"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSearchTimelineInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "searchType": {
            "default": "web",
            "description": "Search Console's search type: web (default), image, video, news, discover or googleNews. Discover and Google News report pages but no queries.",
            "type": "string",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ]
          },
          "from": {
            "default": null,
            "description": "Default: 90 days before to.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "description": "Default: the newest day archived.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AddAnnotationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "on": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "The day it happened (UTC)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "deploy",
              "publish",
              "content_update",
              "campaign",
              "technical",
              "note"
            ]
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "detail": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "on",
          "kind",
          "title"
        ],
        "additionalProperties": false
      },
      "ListAnnotationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "default": null,
            "description": "Default: a year before to.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "description": "Default: today.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "includeGoogle": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RemoveAnnotationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ids": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "clientId",
          "ids"
        ],
        "additionalProperties": false
      },
      "GetSerpContentProfileInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "depth": {
            "default": 10,
            "description": "How many organic results to read.",
            "type": "integer",
            "minimum": 3,
            "maximum": 20
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom, 2724 Spain). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "BuildContentBriefInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "relatedKeywords": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "targetUrl": {
            "description": "The page this brief is for, if it exists, so it is not suggested as its own internal link.",
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "pageType": {
            "description": "The kind of page, for its section template: service, blog, case_study, category, landing, faq, location, about or homepage. Default: guessed from the search intent.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "service",
                  "blog",
                  "case_study",
                  "category",
                  "landing",
                  "faq",
                  "location",
                  "about",
                  "homepage"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "default": 10,
            "type": "integer",
            "minimum": 3,
            "maximum": 20
          },
          "save": {
            "default": false,
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom, 2724 Spain). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "ScoreContentInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "html": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 3000000
              },
              {
                "type": "null"
              }
            ]
          },
          "markdown": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000000
              },
              {
                "type": "null"
              }
            ]
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom, 2724 Spain). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "ClusterKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 200,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "listId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "minShared": {
            "default": 3,
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "depth": {
            "default": 10,
            "type": "integer",
            "minimum": 3,
            "maximum": 20
          },
          "mode": {
            "default": "head",
            "description": "head: every keyword overlaps the topic's top keyword (plan pages with this). connected: chains of overlap join topics.",
            "type": "string",
            "enum": [
              "head",
              "connected"
            ]
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetTopicMapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seed": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "extraKeywords": {
            "default": [],
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "method": {
            "default": "serp_overlap",
            "type": "string",
            "enum": [
              "serp_overlap",
              "search_console"
            ]
          },
          "limit": {
            "default": 100,
            "description": "How many Search Console queries to map, most impressions first.",
            "type": "integer",
            "minimum": 10,
            "maximum": 200
          },
          "minShared": {
            "default": 3,
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CompareCrawlsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "againstCrawlId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "sample": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetIssueTemplatesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "indexableOnly": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetParameterReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCrawlSettingsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SetCrawlSettingsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "stripParams": {
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 60
            }
          },
          "extractions": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 40
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "css",
                    "xpath",
                    "regex",
                    "jsonld",
                    "meta"
                  ]
                },
                "expression": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300
                },
                "attribute": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 60
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "all": {
                  "type": "boolean"
                }
              },
              "required": [
                "name",
                "kind",
                "expression"
              ]
            }
          },
          "render": {
            "type": "string",
            "enum": [
              "off",
              "shells",
              "all"
            ]
          },
          "renderMaxPages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5000
          },
          "mode": {
            "type": "string",
            "enum": [
              "spider",
              "list",
              "sitemap"
            ]
          },
          "listUrls": {
            "maxItems": 5000,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "includePatterns": {
            "maxItems": 25,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "excludePatterns": {
            "maxItems": 25,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "userAgent": {
            "type": "object",
            "properties": {
              "preset": {
                "type": "string",
                "enum": [
                  "seolyticize",
                  "googlebot-smartphone",
                  "googlebot-desktop",
                  "bingbot",
                  "chrome",
                  "custom"
                ]
              },
              "custom": {
                "anyOf": [
                  {
                    "type": "string",
                    "maxLength": 400
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "preset"
            ]
          },
          "requestsPerSecond": {
            "type": "number",
            "minimum": 0.2,
            "maximum": 10
          },
          "concurrency": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          },
          "maxDepth": {
            "type": "integer",
            "minimum": 0,
            "maximum": 50
          },
          "maxPages": {
            "type": "integer",
            "minimum": 1,
            "maximum": 20000
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SetCrawlAuthInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "basicAuth": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "password": {
                    "type": "string",
                    "maxLength": 500
                  }
                },
                "required": [
                  "username",
                  "password"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "headers": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                },
                "value": {
                  "type": "string",
                  "maxLength": 2000
                }
              },
              "required": [
                "name",
                "value"
              ]
            }
          },
          "cookies": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "clear": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPageDetailsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetExtractionResultsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "name": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetRenderingReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetInternalLinkGraphInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "sort": {
            "default": "pagerank",
            "type": "string",
            "enum": [
              "pagerank",
              "inlinks",
              "depth"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SuggestInternalLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "targetUrl": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "phrases": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 100
            }
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "format": {
            "default": "suggestions",
            "type": "string",
            "enum": [
              "suggestions",
              "patch"
            ]
          },
          "sources": {
            "default": [],
            "description": "The linking pages' own source, for diffs against what the CMS stores.",
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "html": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 3000000
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "markdown": {
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 1000000
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "url"
              ]
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAnchorOverlapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetConversionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "source": {
            "default": "web_analytics",
            "type": "string",
            "enum": [
              "web_analytics",
              "ga4"
            ]
          },
          "by": {
            "default": "landing_page",
            "type": "string",
            "enum": [
              "landing_page",
              "source",
              "referrer"
            ]
          },
          "channel": {
            "default": "all",
            "type": "string",
            "enum": [
              "all",
              "search",
              "ai"
            ]
          },
          "goals": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 64
            }
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListConversionGoalsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetReferringDomainsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "default": null,
            "description": "Any domain; default the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBacklinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "default": null,
            "description": "Any domain; default the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "mode": {
            "default": "all",
            "type": "string",
            "enum": [
              "all",
              "new",
              "lost"
            ]
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAnchorDistributionInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "default": null,
            "description": "Any domain; default the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "moneyTerms": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBestPagesByLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "default": null,
            "description": "Any domain; default the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBrokenBacklinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCompetitorNewPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 7,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "competitors": {
            "default": null,
            "anyOf": [
              {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 253
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetCompetitorPageChangesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "default": null,
            "description": "Default: every tracker of the client.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSerpVolatilityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "default": null,
            "description": "Default: every tracker of the client.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 7,
            "maximum": 180
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiOverviewCitationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "default": null,
            "description": "Default: every tracker of the client.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "feature": {
            "default": "ai_overview",
            "type": "string",
            "enum": [
              "ai_overview",
              "featured_snippet",
              "people_also_ask"
            ]
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DescribeDatasetsInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "QueryDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "dataset": {
            "type": "string",
            "enum": [
              "gsc",
              "web_events",
              "crawl_pages",
              "crawl_issues",
              "crawl_links",
              "rank_captures",
              "backlinks",
              "revenue_orders",
              "web_agent_visits"
            ]
          },
          "dimensions": {
            "default": [],
            "maxItems": 6,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "metrics": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "columns": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "filters": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "column": {
                  "type": "string",
                  "minLength": 1
                },
                "op": {
                  "type": "string",
                  "enum": [
                    "eq",
                    "neq",
                    "contains",
                    "not_contains",
                    "starts_with",
                    "gt",
                    "gte",
                    "lt",
                    "lte",
                    "in",
                    "regex"
                  ]
                },
                "value": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              "required": [
                "column",
                "op",
                "value"
              ]
            }
          },
          "from": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "orderBy": {
            "default": [],
            "description": "Sort by a selected dimension or metric: [{ \"column\": \"sum(clicks)\", \"desc\": true }].",
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "column": {
                  "type": "string",
                  "minLength": 1
                },
                "field": {
                  "type": "string",
                  "minLength": 1
                },
                "desc": {
                  "default": true,
                  "type": "boolean"
                }
              }
            }
          },
          "crawlId": {
            "default": "latest",
            "description": "For crawl datasets: a crawl id or latest.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 1000,
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          }
        },
        "required": [
          "clientId",
          "dataset"
        ],
        "additionalProperties": false
      },
      "ExportDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "dataset": {
            "type": "string",
            "enum": [
              "gsc",
              "web_events",
              "crawl_pages",
              "crawl_issues",
              "crawl_links",
              "rank_captures",
              "backlinks",
              "revenue_orders",
              "web_agent_visits"
            ]
          },
          "dimensions": {
            "default": [],
            "maxItems": 6,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "metrics": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "columns": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "filters": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "column": {
                  "type": "string",
                  "minLength": 1
                },
                "op": {
                  "type": "string",
                  "enum": [
                    "eq",
                    "neq",
                    "contains",
                    "not_contains",
                    "starts_with",
                    "gt",
                    "gte",
                    "lt",
                    "lte",
                    "in",
                    "regex"
                  ]
                },
                "value": {
                  "anyOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "number"
                    },
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "array",
                      "items": {
                        "anyOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ]
                      }
                    }
                  ]
                }
              },
              "required": [
                "column",
                "op",
                "value"
              ]
            }
          },
          "from": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "orderBy": {
            "default": [],
            "description": "Sort by a selected dimension or metric: [{ \"column\": \"sum(clicks)\", \"desc\": true }].",
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "column": {
                  "type": "string",
                  "minLength": 1
                },
                "field": {
                  "type": "string",
                  "minLength": 1
                },
                "desc": {
                  "default": true,
                  "type": "boolean"
                }
              }
            }
          },
          "crawlId": {
            "default": "latest",
            "description": "For crawl datasets: a crawl id or latest.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 1000000,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000000
          },
          "format": {
            "default": "csv",
            "type": "string",
            "enum": [
              "csv",
              "jsonl",
              "parquet"
            ]
          }
        },
        "required": [
          "clientId",
          "dataset"
        ],
        "additionalProperties": false
      },
      "GetDemandMatrixInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "pattern": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "Words with {slot} placeholders, e.g. 'receive sms {service} {country}'."
          },
          "slots": {
            "type": "object",
            "propertyNames": {
              "type": "string",
              "pattern": "^[a-z_]{1,20}$"
            },
            "additionalProperties": {
              "minItems": 1,
              "maxItems": 100,
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1,
                "maxLength": 60
              }
            }
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "minVolume": {
            "default": 10,
            "description": "Below this monthly volume a combination is skip.",
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "pattern",
          "slots"
        ],
        "additionalProperties": false
      },
      "GetRankedKeywordsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "engine": {
            "default": "google",
            "type": "string",
            "enum": [
              "google",
              "amazon",
              "app_store",
              "google_play"
            ]
          },
          "target": {
            "default": null,
            "description": "A domain (competitor.com), a subfolder (competitor.com/blog/) or a page URL. Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "scope": {
            "default": "auto",
            "description": "auto reads a bare domain as the domain, a path ending in / as a subfolder, anything else as one URL.",
            "type": "string",
            "enum": [
              "auto",
              "domain",
              "subdomains",
              "subfolder",
              "url"
            ]
          },
          "paid": {
            "default": false,
            "type": "boolean"
          },
          "resultType": {
            "default": "organic",
            "description": "ai_overview_reference: keywords whose AI Overview cites the domain; featured_snippet; local_pack; paid (same as paid: true).",
            "type": "string",
            "enum": [
              "organic",
              "paid",
              "ai_overview_reference",
              "featured_snippet",
              "local_pack"
            ]
          },
          "change": {
            "default": "all",
            "type": "string",
            "enum": [
              "all",
              "new",
              "up",
              "down",
              "lost"
            ]
          },
          "minPosition": {
            "default": 1,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "maxPosition": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "minVolume": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "intent": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "informational",
                  "navigational",
                  "commercial",
                  "transactional"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "contains": {
            "default": null,
            "description": "Only keywords containing these words.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "sort": {
            "default": "traffic",
            "type": "string",
            "enum": [
              "traffic",
              "volume",
              "position",
              "change"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 100000
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetTopPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "A domain (competitor.com), a subfolder (competitor.com/blog/) or a page URL. Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "scope": {
            "default": "auto",
            "description": "auto reads a bare domain as the domain, a path ending in / as a subfolder, anything else as one URL.",
            "type": "string",
            "enum": [
              "auto",
              "domain",
              "subdomains",
              "subfolder",
              "url"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetDomainOverviewInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "A domain (competitor.com), a subfolder (competitor.com/blog/) or a page URL. Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "locationCodes": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 9007199254740991
            }
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "historyMonths": {
            "default": 12,
            "type": "integer",
            "minimum": 0,
            "maximum": 36
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetKeywordMetricsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "engine": {
            "default": "google",
            "type": "string",
            "enum": [
              "google",
              "bing",
              "amazon",
              "youtube"
            ]
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 700,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCodes": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 9007199254740991
            }
          },
          "locationName": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "clickstream": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "GetBacklinkHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "A domain (competitor.com), a subfolder (competitor.com/blog/) or a page URL. Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "from": {
            "default": null,
            "description": "Default: two years back.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSerpHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "from": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetAiModeAnswerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "device": {
            "default": "desktop",
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetAiBrandMentionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "brands": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 80
                },
                "domains": {
                  "default": [],
                  "maxItems": 10,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 63
                  }
                },
                "keywords": {
                  "default": [],
                  "maxItems": 10,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 250
                  }
                }
              },
              "required": [
                "name"
              ]
            }
          },
          "platform": {
            "default": "google",
            "description": "google: AI Overviews; chat_gpt: ChatGPT (US English only) — both from DataForSEO's database plus Seolyticize's samples. claude, gemini, perplexity, copilot, grok, meta_ai, deepseek, ai_mode: Seolyticize's own sampled answers only (free).",
            "type": "string",
            "enum": [
              "google",
              "chat_gpt",
              "claude",
              "gemini",
              "perplexity",
              "copilot",
              "grok",
              "meta_ai",
              "deepseek",
              "ai_mode"
            ]
          },
          "includeSampled": {
            "default": true,
            "description": "Add Seolyticize's own sampled answers to the client's tracked questions (run_ai_visibility_check), tagged source sampled.",
            "type": "boolean"
          },
          "sampledDays": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "brands"
        ],
        "additionalProperties": false
      },
      "GetAiPromptResearchInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 250
          },
          "platform": {
            "default": "google",
            "description": "google: AI Overviews; chat_gpt: ChatGPT (US English only) — both from DataForSEO's database plus Seolyticize's samples. claude, gemini, perplexity, copilot, grok, meta_ai, deepseek, ai_mode: Seolyticize's own sampled answers only (free).",
            "type": "string",
            "enum": [
              "google",
              "chat_gpt",
              "claude",
              "gemini",
              "perplexity",
              "copilot",
              "grok",
              "meta_ai",
              "deepseek",
              "ai_mode"
            ]
          },
          "limit": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "includeSampled": {
            "default": true,
            "description": "Add Seolyticize's own sampled answers to the client's tracked questions (run_ai_visibility_check), tagged source sampled.",
            "type": "boolean"
          },
          "sampledDays": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetAiSearchVolumeInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "GetAiTopCitedDomainsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "topic": {
            "type": "string",
            "minLength": 1,
            "maxLength": 250
          },
          "platform": {
            "default": "google",
            "description": "google: AI Overviews; chat_gpt: ChatGPT (US English only) — both from DataForSEO's database plus Seolyticize's samples. claude, gemini, perplexity, copilot, grok, meta_ai, deepseek, ai_mode: Seolyticize's own sampled answers only (free).",
            "type": "string",
            "enum": [
              "google",
              "chat_gpt",
              "claude",
              "gemini",
              "perplexity",
              "copilot",
              "grok",
              "meta_ai",
              "deepseek",
              "ai_mode"
            ]
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "includeSampled": {
            "default": true,
            "description": "Add Seolyticize's own sampled answers to the client's tracked questions (run_ai_visibility_check), tagged source sampled.",
            "type": "boolean"
          },
          "sampledDays": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "topic"
        ],
        "additionalProperties": false
      },
      "GetKeywordAdvertisersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project (2840 United States).",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "UpdateBusinessProfileInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "description": "The client's location, from list_local_locations. Default: its one connected location.",
            "type": "string",
            "minLength": 1
          },
          "changes": {
            "type": "object",
            "properties": {
              "description": {
                "type": "string",
                "minLength": 1,
                "maxLength": 750
              },
              "phone": {
                "description": "Primary, and up to two additional; additional defaults to what the listing has.",
                "type": "object",
                "properties": {
                  "primary": {
                    "type": "string",
                    "minLength": 6,
                    "maxLength": 30
                  },
                  "additional": {
                    "maxItems": 2,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 6,
                      "maxLength": 30
                    }
                  }
                },
                "required": [
                  "primary"
                ]
              },
              "website": {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              "categories": {
                "description": "Google category ids such as gcid:dentist; additional defaults to what the listing has.",
                "type": "object",
                "properties": {
                  "primary": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "additional": {
                    "maxItems": 9,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    }
                  }
                },
                "required": [
                  "primary"
                ]
              },
              "regularHours": {
                "description": "The whole week: every period the listing is open (a day not listed is closed). close may be 24:00; closeDay for hours past midnight.",
                "maxItems": 28,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "day": {
                      "type": "string",
                      "enum": [
                        "MONDAY",
                        "TUESDAY",
                        "WEDNESDAY",
                        "THURSDAY",
                        "FRIDAY",
                        "SATURDAY",
                        "SUNDAY"
                      ]
                    },
                    "open": {
                      "type": "string",
                      "pattern": "^\\d{1,2}:\\d{2}$"
                    },
                    "close": {
                      "type": "string",
                      "pattern": "^\\d{1,2}:\\d{2}$"
                    },
                    "closeDay": {
                      "type": "string",
                      "enum": [
                        "MONDAY",
                        "TUESDAY",
                        "WEDNESDAY",
                        "THURSDAY",
                        "FRIDAY",
                        "SATURDAY",
                        "SUNDAY"
                      ]
                    }
                  },
                  "required": [
                    "day",
                    "open",
                    "close"
                  ]
                }
              },
              "specialHours": {
                "description": "Holidays and one-off hours: each date closed, or open between open and close. Replaces the listing's special hours.",
                "maxItems": 100,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                    },
                    "closed": {
                      "type": "boolean"
                    },
                    "open": {
                      "type": "string",
                      "pattern": "^\\d{1,2}:\\d{2}$"
                    },
                    "close": {
                      "type": "string",
                      "pattern": "^\\d{1,2}:\\d{2}$"
                    }
                  },
                  "required": [
                    "date"
                  ]
                }
              },
              "attributes": {
                "description": "Yes/no attributes by Google id, e.g. has_wheelchair_accessible_entrance.",
                "type": "object",
                "propertyNames": {
                  "type": "string",
                  "pattern": "^(attributes\\/)?[a-z0-9_]+$"
                },
                "additionalProperties": {
                  "type": "boolean"
                }
              }
            },
            "additionalProperties": false
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "changes"
        ],
        "additionalProperties": false
      },
      "CreateBusinessPostInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "description": "The client's location, from list_local_locations. Default: its one connected location.",
            "type": "string",
            "minLength": 1
          },
          "summary": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1500
          },
          "callToAction": {
            "type": "object",
            "properties": {
              "actionType": {
                "type": "string",
                "enum": [
                  "BOOK",
                  "ORDER",
                  "SHOP",
                  "LEARN_MORE",
                  "SIGN_UP",
                  "CALL"
                ]
              },
              "url": {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              }
            },
            "required": [
              "actionType"
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "summary"
        ],
        "additionalProperties": false
      },
      "GetHreflangParityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "sourceLang": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 20
              },
              {
                "type": "null"
              }
            ]
          },
          "maxPairs": {
            "default": 12,
            "type": "integer",
            "minimum": 1,
            "maximum": 40
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GenerateHreflangInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "xDefault": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 20
              },
              {
                "type": "null"
              }
            ]
          },
          "method": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "html",
              "http",
              "sitemap"
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSxoGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "keyword": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "personas": {
            "default": false,
            "type": "boolean"
          },
          "wireframe": {
            "default": true,
            "type": "boolean"
          },
          "deep": {
            "default": false,
            "description": "Also render the page on a phone and score its E-E-A-T, and read UX and authority from those (free, slower).",
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "BuildComparisonPageInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "pageType": {
            "type": "string",
            "enum": [
              "vs",
              "alternatives",
              "roundup",
              "table"
            ]
          },
          "competitors": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 80
                },
                "domain": {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 200
                }
              },
              "required": [
                "name",
                "domain"
              ]
            }
          },
          "features": {
            "default": [],
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 80
            }
          },
          "sourceUrls": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "category": {
            "default": null,
            "description": "For a roundup: what the tools are, e.g. 'CRM'.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 80
              },
              {
                "type": "null"
              }
            ]
          },
          "demand": {
            "default": true,
            "type": "boolean"
          },
          "instructions": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "pageType",
          "competitors"
        ],
        "additionalProperties": false
      },
      "SetKeywordOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "owners": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "keyword": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "cluster": {
                  "default": [],
                  "maxItems": 100,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  }
                },
                "url": {
                  "type": "string",
                  "maxLength": 2000,
                  "format": "uri"
                },
                "note": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 500
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "keyword",
                "url"
              ]
            }
          },
          "source": {
            "default": "manual",
            "type": "string",
            "enum": [
              "manual",
              "search_console"
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "owners"
        ],
        "additionalProperties": false
      },
      "ListKeywordOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RemoveKeywordOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "ProposeKeywordOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "limit": {
            "default": 300,
            "type": "integer",
            "minimum": 10,
            "maximum": 2000
          },
          "seed": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetTopicalAuthorityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "seed": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "extraKeywords": {
            "default": [],
            "maxItems": 300,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "limit": {
            "default": 500,
            "type": "integer",
            "minimum": 10,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetEntityCoverageInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "html": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 3000000
              },
              {
                "type": "null"
              }
            ]
          },
          "markdown": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000000
              },
              {
                "type": "null"
              }
            ]
          },
          "resolve": {
            "default": true,
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetFreshnessQueueInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckProgrammaticPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "template": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "minVariants": {
            "default": 10,
            "type": "integer",
            "minimum": 3,
            "maximum": 1000
          },
          "limit": {
            "default": 5,
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSnippetTargetsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 25
          },
          "draft": {
            "default": true,
            "type": "boolean"
          },
          "readMissing": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "PlanContentInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "months": {
            "default": 3,
            "type": "integer",
            "minimum": 1,
            "maximum": 12
          },
          "cadence": {
            "default": "weekly",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "weekly",
                  "fortnightly",
                  "monthly"
                ]
              },
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 30
              }
            ]
          },
          "startMonth": {
            "default": null,
            "description": "Default: next month.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}(-01)?$"
              },
              {
                "type": "null"
              }
            ]
          },
          "seed": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "extraKeywords": {
            "default": [],
            "maxItems": 300,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "trends": {
            "default": false,
            "type": "boolean"
          },
          "includeRefreshes": {
            "default": true,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListContentPlanInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}(-01)?$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}(-01)?$"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "planned",
                "briefed",
                "drafting",
                "published",
                "dropped"
              ]
            }
          },
          "planId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "UpdateContentPlanItemInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "id": {
            "type": "string",
            "minLength": 1
          },
          "month": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}(-01)?$"
          },
          "publishOn": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "planned",
              "briefed",
              "drafting",
              "published",
              "dropped"
            ]
          },
          "targetUrl": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          }
        },
        "required": [
          "clientId",
          "id"
        ],
        "additionalProperties": false
      },
      "GetAiReferralsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiCitationHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 400
          },
          "engine": {
            "default": null,
            "description": "One assistant (chatgpt, perplexity, gemini, claude, google-aio, …); default all.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiAnswerShareInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "weeks": {
            "default": 12,
            "type": "integer",
            "minimum": 1,
            "maximum": 52
          },
          "engine": {
            "default": null,
            "description": "One assistant (chatgpt, perplexity, gemini, claude, google-aio, …); default all.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiCrawlerAccessInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "pages": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "log": {
            "default": null,
            "description": "An access log in combined format, as analyse_server_log takes it.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 67108864
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckAnswerReadinessInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "topPages": {
            "default": 10,
            "type": "integer",
            "minimum": 0,
            "maximum": 20
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SetClientFactsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "facts": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "minLength": 2,
                  "maxLength": 120
                },
                "value": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500
                },
                "category": {
                  "default": "other",
                  "type": "string",
                  "enum": [
                    "price",
                    "limit",
                    "country",
                    "date",
                    "contact",
                    "other"
                  ]
                },
                "terms": {
                  "default": [],
                  "maxItems": 10,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 60
                  }
                },
                "sourceUrl": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "format": "uri"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "key",
                "value"
              ]
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "facts"
        ],
        "additionalProperties": false
      },
      "ImportClientFactsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "content": {
            "type": "string",
            "maxLength": 200000
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListClientFactsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RemoveClientFactsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keys": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 120
            }
          }
        },
        "required": [
          "clientId",
          "keys"
        ],
        "additionalProperties": false
      },
      "GetLlmResponsesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "prompt": {
            "type": "string",
            "minLength": 3,
            "maxLength": 500
          },
          "platforms": {
            "default": [
              "chat_gpt",
              "perplexity"
            ],
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "chat_gpt",
                "chat_gpt_app",
                "claude",
                "gemini",
                "perplexity"
              ]
            }
          },
          "webSearch": {
            "default": true,
            "type": "boolean"
          },
          "country": {
            "default": null,
            "description": "Where the web search runs from (ChatGPT, Claude and Perplexity's Sonar models).",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^[a-zA-Z]{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "models": {
            "default": {},
            "description": "A model per platform; defaults gpt-5-mini, claude-sonnet-4-6, gemini-2.5-flash, sonar.",
            "type": "object",
            "properties": {
              "chat_gpt": {
                "type": "string",
                "minLength": 2,
                "maxLength": 80
              },
              "claude": {
                "type": "string",
                "minLength": 2,
                "maxLength": 80
              },
              "gemini": {
                "type": "string",
                "minLength": 2,
                "maxLength": 80
              },
              "perplexity": {
                "type": "string",
                "minLength": 2,
                "maxLength": 80
              }
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "prompt"
        ],
        "additionalProperties": false
      },
      "SuggestAiVisibilitySetupInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seedKeywords": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "maxSeeds": {
            "default": 3,
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "promptsPerSeed": {
            "default": 5,
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          },
          "maxCompetitors": {
            "default": 5,
            "type": "integer",
            "minimum": 0,
            "maximum": 10
          },
          "platform": {
            "default": "google",
            "description": "Which AI answer index the questions come from.",
            "type": "string",
            "enum": [
              "google",
              "chat_gpt"
            ]
          },
          "apply": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBusinessProfileInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "business": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200,
            "description": "The business name (best with the town), or cid:123… / place_id:ChIJ… for an exact listing."
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "lat": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -90,
                "maximum": 90
              },
              {
                "type": "null"
              }
            ]
          },
          "lng": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -180,
                "maximum": 180
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "business"
        ],
        "additionalProperties": false
      },
      "SearchLocalBusinessesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "radiusKm": {
            "default": 10,
            "type": "number",
            "minimum": 1,
            "maximum": 500
          },
          "categories": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 80
            }
          },
          "name": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "minRating": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 5
              },
              {
                "type": "null"
              }
            ]
          },
          "claimed": {
            "default": null,
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "GetBusinessQuestionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "business": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200,
            "description": "The business name (best with the town), or cid:123… / place_id:ChIJ… for an exact listing."
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "lat": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -90,
                "maximum": 90
              },
              {
                "type": "null"
              }
            ]
          },
          "lng": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -180,
                "maximum": 180
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "business"
        ],
        "additionalProperties": false
      },
      "GetLocalCategoriesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lng": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "radiusKm": {
            "default": 10,
            "type": "number",
            "minimum": 1,
            "maximum": 500
          },
          "categories": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 80
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "lat",
          "lng"
        ],
        "additionalProperties": false
      },
      "GetMapsResultsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "surface": {
            "default": "maps",
            "type": "string",
            "enum": [
              "maps",
              "local_finder"
            ]
          },
          "zoom": {
            "default": 14,
            "type": "integer",
            "minimum": 3,
            "maximum": 21
          },
          "depth": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "lat": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -90,
                "maximum": 90
              },
              {
                "type": "null"
              }
            ]
          },
          "lng": {
            "default": null,
            "anyOf": [
              {
                "type": "number",
                "minimum": -180,
                "maximum": 180
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetBusinessReviewsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "business": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 200,
                "description": "The business name (best with the town), or cid:123… / place_id:ChIJ… for an exact listing."
              },
              {
                "type": "null"
              }
            ]
          },
          "taskId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 80
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "default": 100,
            "type": "integer",
            "minimum": 10,
            "maximum": 500
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBusinessPostsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "business": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 200,
                "description": "The business name (best with the town), or cid:123… / place_id:ChIJ… for an exact listing."
              },
              {
                "type": "null"
              }
            ]
          },
          "taskId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 80
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "default": 20,
            "description": "How many posts to read; each ten more costs a little more.",
            "type": "integer",
            "minimum": 10,
            "maximum": 100
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPlatformReviewsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "platform": {
            "type": "string",
            "enum": [
              "tripadvisor",
              "trustpilot"
            ]
          },
          "business": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "taskId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 80
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "default": 40,
            "description": "How many reviews to read; billed per 10 (Tripadvisor) or 20 (Trustpilot).",
            "type": "integer",
            "minimum": 10,
            "maximum": 200
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project country.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "platform"
        ],
        "additionalProperties": false
      },
      "SearchLocationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "query": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "country": {
            "default": "us",
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO country code: us, gb, de…"
          },
          "type": {
            "default": null,
            "description": "Only this kind: City, County, State, Region, DMA Region, Postal Code…",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId",
          "query"
        ],
        "additionalProperties": false
      },
      "GetLandingPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetTrackerAiModeInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "trackerId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "trackerId"
        ],
        "additionalProperties": false
      },
      "GetAuditPerformanceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\".",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RunAuditPerformanceSampleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "PlanRedirectMapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "newCrawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          },
          "oldUrls": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 10000,
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uri"
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "oldSitemapUrl": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "oldCrawlId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "format": {
            "default": "json",
            "type": "string",
            "enum": [
              "json",
              "csv",
              "htaccess",
              "nginx"
            ]
          },
          "minConfidence": {
            "default": 0,
            "type": "number",
            "minimum": 0,
            "maximum": 1
          },
          "limit": {
            "default": 500,
            "type": "integer",
            "minimum": 1,
            "maximum": 10000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SimulateSerpSnippetInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "title": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "description": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "InviteTeamMemberInput": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "maxLength": 254,
            "format": "email",
            "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
          },
          "role": {
            "type": "string",
            "enum": [
              "admin",
              "manager",
              "analyst",
              "client_viewer"
            ]
          },
          "clientIds": {
            "default": [],
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          }
        },
        "required": [
          "email",
          "role"
        ],
        "additionalProperties": false
      },
      "ListTeamInvitesInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "ResendTeamInviteInput": {
        "type": "object",
        "properties": {
          "inviteId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "inviteId"
        ],
        "additionalProperties": false
      },
      "RevokeTeamInviteInput": {
        "type": "object",
        "properties": {
          "inviteId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "inviteId"
        ],
        "additionalProperties": false
      },
      "ListTasksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "statuses": {
            "default": [],
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "todo",
                "in_progress",
                "done",
                "wont_do"
              ]
            }
          },
          "assigneeUserId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "unassignedOnly": {
            "default": false,
            "type": "boolean"
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateTaskInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "notes": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 8000
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "default": "todo",
            "type": "string",
            "enum": [
              "todo",
              "in_progress",
              "done",
              "wont_do"
            ]
          },
          "assigneeUserId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "description": "A user id from list_team_members (the member's userId). They must be able to open this client."
          },
          "dueDate": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "YYYY-MM-DD."
          },
          "link": {
            "default": null,
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "issue",
                      "url",
                      "keyword"
                    ]
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2048
                  }
                },
                "required": [
                  "kind",
                  "value"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "What the task is about: an audit issue (value: its ruleId from list_crawl_issues), a page (an absolute URL) or a keyword."
          },
          "crawlId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "title"
        ],
        "additionalProperties": false
      },
      "UpdateTaskInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "taskId": {
            "type": "string",
            "minLength": 1
          },
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300
          },
          "notes": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 8000
              },
              {
                "type": "null"
              }
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "todo",
              "in_progress",
              "done",
              "wont_do"
            ]
          },
          "assigneeUserId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "description": "A user id from list_team_members (the member's userId). They must be able to open this client."
          },
          "dueDate": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "YYYY-MM-DD."
          },
          "link": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "issue",
                      "url",
                      "keyword"
                    ]
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2048
                  }
                },
                "required": [
                  "kind",
                  "value"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "What the task is about: an audit issue (value: its ruleId from list_crawl_issues), a page (an absolute URL) or a keyword."
          }
        },
        "required": [
          "clientId",
          "taskId"
        ],
        "additionalProperties": false
      },
      "DeleteTaskInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "taskId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "taskId"
        ],
        "additionalProperties": false
      },
      "CreateTasksFromAuditInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          },
          "ruleIds": {
            "default": null,
            "description": "Only these issues; null takes every issue of the chosen severities.",
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 200,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 100
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "severities": {
            "default": [
              "critical",
              "warning"
            ],
            "minItems": 1,
            "maxItems": 3,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "critical",
                "warning",
                "notice"
              ]
            }
          },
          "assigneeUserId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "description": "A user id from list_team_members (the member's userId). They must be able to open this client."
          },
          "dueDate": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ],
            "description": "YYYY-MM-DD."
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListPortfoliosInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "CreatePortfolioInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "members": {
            "default": [],
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "clientId": {
                  "type": "string",
                  "minLength": 1
                },
                "siteId": {
                  "default": null,
                  "description": "One site of the client; null puts the whole client in the portfolio.",
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "clientId"
              ]
            }
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "UpdatePortfolioInput": {
        "type": "object",
        "properties": {
          "portfolioId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 1000
              },
              {
                "type": "null"
              }
            ]
          },
          "add": {
            "default": [],
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "clientId": {
                  "type": "string",
                  "minLength": 1
                },
                "siteId": {
                  "default": null,
                  "description": "One site of the client; null puts the whole client in the portfolio.",
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "clientId"
              ]
            }
          },
          "remove": {
            "default": [],
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "clientId": {
                  "type": "string",
                  "minLength": 1
                },
                "siteId": {
                  "default": null,
                  "description": "One site of the client; null puts the whole client in the portfolio.",
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "clientId"
              ]
            }
          }
        },
        "required": [
          "portfolioId"
        ],
        "additionalProperties": false
      },
      "DeletePortfolioInput": {
        "type": "object",
        "properties": {
          "portfolioId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "portfolioId"
        ],
        "additionalProperties": false
      },
      "GetPortfolioMetricsInput": {
        "type": "object",
        "properties": {
          "portfolioId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "portfolioId"
        ],
        "additionalProperties": false
      },
      "GetIndexnowKeyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "IssueIndexnowKeyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "VerifyIndexnowKeyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "BuildDisavowFileInput": {
        "type": "object",
        "properties": {
          "entries": {
            "minItems": 1,
            "maxItems": 5000,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sourceDomain": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 253
                },
                "scope": {
                  "type": "string",
                  "enum": [
                    "domain",
                    "url"
                  ]
                },
                "url": {
                  "type": "string",
                  "maxLength": 2048
                }
              },
              "required": [
                "sourceDomain",
                "scope"
              ]
            }
          }
        },
        "required": [
          "entries"
        ],
        "additionalProperties": false
      },
      "QueueUrlInspectionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 2048
            }
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "NotifyGoogleIndexingInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2048,
              "format": "uri"
            }
          },
          "type": {
            "default": "URL_UPDATED",
            "type": "string",
            "enum": [
              "URL_UPDATED",
              "URL_DELETED"
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "GetContentAuditInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "verdict": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "keep",
                  "update",
                  "merge",
                  "review",
                  "no_search_data"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 500,
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckNapConsistencyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "useListing": {
            "default": true,
            "type": "boolean"
          },
          "directories": {
            "default": false,
            "type": "boolean"
          },
          "industryDirectories": {
            "default": null,
            "description": "Extra directory domains for the trade, e.g. avvo.com, healthgrades.com. Null searches the trade's own directories, detected from the listing's categories and the site: OpenTable and delivery apps for a restaurant, Healthgrades and Zocdoc for healthcare, Avvo, FindLaw and Justia for legal, Zillow and Realtor.com for real estate, Cars.com and DealerRater for automotive. [] searches the general ones only.",
            "anyOf": [
              {
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 3,
                  "maxLength": 253
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "locationId"
        ],
        "additionalProperties": false
      },
      "GetTrustSignalsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetParasiteRiskInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckTemplatedMetadataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiCitationGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ourUrl": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "promptId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "question": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 5,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "citedUrls": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "ourUrl"
        ],
        "additionalProperties": false
      },
      "CheckAiBrandAccuracyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "facts": {
            "default": [],
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 5,
              "maxLength": 300
            }
          },
          "question": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 5,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "platforms": {
            "default": [
              "chat_gpt_app",
              "perplexity"
            ],
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "chat_gpt_app",
                "perplexity",
                "chat_gpt",
                "claude",
                "gemini"
              ]
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GenerateSchemaInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "type": {
            "default": null,
            "description": "A type to write even where the page would not suggest it.",
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "Product",
                  "ProductGroup",
                  "Article",
                  "FAQPage",
                  "HowTo",
                  "SoftwareApplication",
                  "Service",
                  "Organization",
                  "LocalBusiness",
                  "VideoObject",
                  "ProfilePage",
                  "QAPage",
                  "DiscussionForumPosting",
                  "ItemList",
                  "SoftwareSourceCode"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "localBusinessType": {
            "default": null,
            "description": "The schema.org LocalBusiness subtype, e.g. Dentist or LegalService.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 60,
                "pattern": "^[A-Z][A-Za-z]+$"
              },
              {
                "type": "null"
              }
            ]
          },
          "openingHours": {
            "default": [],
            "description": "As the Business Profile lists them, HH:MM.",
            "maxItems": 14,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "days": {
                  "minItems": 1,
                  "maxItems": 8,
                  "type": "array",
                  "items": {
                    "type": "string",
                    "enum": [
                      "Monday",
                      "Tuesday",
                      "Wednesday",
                      "Thursday",
                      "Friday",
                      "Saturday",
                      "Sunday",
                      "PublicHolidays"
                    ]
                  }
                },
                "opens": {
                  "type": "string",
                  "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                },
                "closes": {
                  "type": "string",
                  "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$"
                }
              },
              "required": [
                "days",
                "opens",
                "closes"
              ]
            }
          },
          "areaServed": {
            "default": [],
            "description": "For a service-area business: the towns or regions it serves.",
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          "shipping": {
            "default": null,
            "description": "The shop's shipping to one country, for Product offers.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "rate": {
                    "type": "number",
                    "minimum": 0
                  },
                  "currency": {
                    "type": "string",
                    "pattern": "^[A-Z]{3}$"
                  },
                  "handlingDays": {
                    "type": "array",
                    "prefixItems": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 60
                      },
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 60
                      }
                    ]
                  },
                  "transitDays": {
                    "type": "array",
                    "prefixItems": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 60
                      },
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 60
                      }
                    ]
                  }
                },
                "required": [
                  "country",
                  "rate",
                  "currency",
                  "handlingDays",
                  "transitDays"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "returns": {
            "default": null,
            "description": "The return policy: days null for no limit, 0 for no returns.",
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "country": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  },
                  "days": {
                    "anyOf": [
                      {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 365
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "fees": {
                    "default": null,
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "free",
                          "customer"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "method": {
                    "default": null,
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "mail",
                          "store"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "country",
                  "days"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GenerateLlmsTxtInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "maxLinks": {
            "default": 40,
            "type": "integer",
            "minimum": 5,
            "maximum": 200
          },
          "summary": {
            "default": null,
            "description": "The one-line summary; default the homepage's description.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 10,
                "maxLength": 400
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetGeoReadinessInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "topPages": {
            "default": 10,
            "type": "integer",
            "minimum": 0,
            "maximum": 20
          },
          "brandMentions": {
            "default": false,
            "description": "Also count the brand's mentions on the web, Reddit, YouTube, LinkedIn and Wikipedia from Google search: five paid results pages (quote with estimate_cost).",
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckBrandEntityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "brand": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 120
              },
              {
                "type": "null"
              }
            ]
          },
          "languages": {
            "default": [
              "en"
            ],
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "pattern": "^[a-z]{2}$"
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAgentReadinessInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "render": {
            "default": true,
            "description": "Render the homepage in a browser for the accessibility tree.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DraftAgentFilesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "aiTrain": {
            "type": "string",
            "enum": [
              "yes",
              "no"
            ],
            "description": "Whether the content may be used to train AI models."
          },
          "aiInput": {
            "default": "yes",
            "description": "Whether it may ground AI answers (retrieval).",
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "search": {
            "default": "yes",
            "description": "Whether it may be indexed for search.",
            "type": "string",
            "enum": [
              "yes",
              "no"
            ]
          },
          "urls": {
            "default": [],
            "description": "Pages whose forms to stub, besides the homepage.",
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          }
        },
        "required": [
          "clientId",
          "aiTrain"
        ],
        "additionalProperties": false
      },
      "CheckUrlSafetyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "outbound": {
            "default": true,
            "description": "Also check the external sites the homepage links to (up to 40).",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DraftReviewRepliesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 25
          },
          "voice": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "includeAnswered": {
            "default": false,
            "type": "boolean"
          },
          "trade": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "healthcare",
              "legal",
              "general"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "locationId"
        ],
        "additionalProperties": false
      },
      "DraftOutreachEmailsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "prospectIds": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "offer": {
            "type": "string",
            "minLength": 5,
            "maxLength": 600,
            "description": "What the client offers: the replacement page, the data, the guest piece."
          },
          "ourUrl": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "sender": {
            "default": null,
            "description": "Who signs it.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 120
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "prospectIds",
          "offer"
        ],
        "additionalProperties": false
      },
      "PostReviewReplyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "locationId": {
            "type": "string",
            "minLength": 1
          },
          "reviewId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "reply": {
            "type": "string",
            "minLength": 2,
            "maxLength": 4000
          }
        },
        "required": [
          "clientId",
          "locationId",
          "reviewId",
          "reply"
        ],
        "additionalProperties": false
      },
      "GetDomainKeywordGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "competitors": {
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "mode": {
            "default": "missing",
            "type": "string",
            "enum": [
              "missing",
              "shared",
              "weak"
            ]
          },
          "minVolume": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9007199254740991
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "competitors"
        ],
        "additionalProperties": false
      },
      "GetLinkGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "Default: the client's own domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "competitors": {
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "match": {
            "default": "any",
            "type": "string",
            "enum": [
              "any",
              "all"
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "competitors"
        ],
        "additionalProperties": false
      },
      "GetBatchAnalysisInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "targets": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 500
            }
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "targets"
        ],
        "additionalProperties": false
      },
      "GetGoogleTrendsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          "timeRange": {
            "default": "past_12_months",
            "type": "string",
            "enum": [
              "past_30_days",
              "past_90_days",
              "past_12_months",
              "past_5_years",
              "2004_present"
            ]
          },
          "type": {
            "default": "web",
            "type": "string",
            "enum": [
              "web",
              "news",
              "youtube",
              "images",
              "froogle"
            ]
          },
          "worldwide": {
            "default": false,
            "description": "true ignores the market and reads the whole world.",
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "description": "Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "FindUnlinkedMentionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "brand": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "since": {
            "default": null,
            "description": "Only pages published since; default the last year.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPageBacklinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "dofollowOnly": {
            "default": false,
            "type": "boolean"
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetCompetitorBrokenPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "type": "string",
            "minLength": 3,
            "maxLength": 253,
            "description": "The competitor's domain."
          },
          "source": {
            "default": "auto",
            "type": "string",
            "enum": [
              "auto",
              "vendor",
              "index"
            ]
          },
          "dofollowOnly": {
            "default": true,
            "description": "Only pages with at least one dofollow referring domain.",
            "type": "boolean"
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "domain"
        ],
        "additionalProperties": false
      },
      "GetOutboundDomainsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domain": {
            "default": null,
            "description": "Any domain; default the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetForumOpportunitiesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "days": {
            "default": 30,
            "description": "For tracked keywords: how old a capture may be.",
            "type": "integer",
            "minimum": 1,
            "maximum": 90
          },
          "maxPosition": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 30
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SearchWebContentInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200
          },
          "exact": {
            "default": true,
            "description": "Match the phrase as written.",
            "type": "boolean"
          },
          "inTitle": {
            "default": false,
            "description": "Only pages with it in the title.",
            "type": "boolean"
          },
          "pageTypes": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ecommerce",
                "news",
                "blogs",
                "message-boards",
                "organization"
              ]
            }
          },
          "sentiment": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "positive",
                  "negative",
                  "neutral"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "since": {
            "default": null,
            "description": "Only pages published on or after this date.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "minDomainRank": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 1000
          },
          "excludeDomain": {
            "default": null,
            "description": "Leave this domain out, usually the client's own.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "onePerDomain": {
            "default": false,
            "type": "boolean"
          },
          "sort": {
            "default": "relevance",
            "type": "string",
            "enum": [
              "relevance",
              "newest",
              "domain_rank"
            ]
          },
          "summary": {
            "default": true,
            "description": "Also read the summary of the whole set (a second lookup).",
            "type": "boolean"
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 9000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "FindLinkOpportunitiesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "topic": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "kinds": {
            "default": [
              "resource_pages",
              "best_lists",
              "roundups"
            ],
            "minItems": 1,
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "resource_pages",
                "best_lists",
                "roundups",
                "podcasts",
                "newsletters"
              ]
            }
          },
          "queriesPerKind": {
            "default": 1,
            "type": "integer",
            "minimum": 1,
            "maximum": 4
          },
          "depth": {
            "default": 20,
            "type": "integer",
            "minimum": 10,
            "maximum": 50
          },
          "excludeDomains": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "addToList": {
            "default": false,
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "topic"
        ],
        "additionalProperties": false
      },
      "FindJournalistRequestsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "feeds": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "keywords": {
            "default": [],
            "maxItems": 30,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          "days": {
            "default": 7,
            "type": "integer",
            "minimum": 1,
            "maximum": 60
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          },
          "addToList": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DraftArticleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "relatedKeywords": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "wordCount": {
            "description": "Length to aim for. Default: the median of the ranking pages.",
            "anyOf": [
              {
                "type": "integer",
                "minimum": 300,
                "maximum": 5000
              },
              {
                "type": "null"
              }
            ]
          },
          "instructions": {
            "description": "Anything the writer should know: angle, product, what to avoid.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "targetUrl": {
            "description": "The page this draft is for, when it rewrites one.",
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "depth": {
            "default": 10,
            "type": "integer",
            "minimum": 3,
            "maximum": 20
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "RewriteSectionInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "section": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30000,
            "description": "The section, Markdown or text."
          },
          "mode": {
            "default": "rewrite",
            "type": "string",
            "enum": [
              "rewrite",
              "extend"
            ]
          },
          "missingTerms": {
            "maxItems": 40,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "questions": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 300
            }
          },
          "draft": {
            "description": "The whole page as Markdown, scored to find what is missing.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 500000
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "anyOf": [
              {
                "type": "string",
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "instructions": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000
              },
              {
                "type": "null"
              }
            ]
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword",
          "section"
        ],
        "additionalProperties": false
      },
      "SuggestMetaTagsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "urls": {
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uri"
            }
          },
          "problems": {
            "default": [
              "missing",
              "duplicate",
              "too_long",
              "too_short"
            ],
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "missing",
                "duplicate",
                "too_long",
                "too_short"
              ]
            }
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "format": {
            "default": "rows",
            "type": "string",
            "enum": [
              "rows",
              "csv"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ForecastKeywordTrafficInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "term": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "searchVolume": {
                  "anyOf": [
                    {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 9007199254740991
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "difficulty": {
                  "anyOf": [
                    {
                      "type": "number",
                      "minimum": 0,
                      "maximum": 100
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "term"
              ]
            }
          },
          "positions": {
            "default": [
              1,
              3,
              5,
              10
            ],
            "minItems": 1,
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "ResearchTopicInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seed": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 10,
            "maximum": 500
          },
          "serp": {
            "default": true,
            "description": "Also read the results page for People Also Ask and headlines.",
            "type": "boolean"
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "seed"
        ],
        "additionalProperties": false
      },
      "GetPersonalKeywordDifficultyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": null,
            "description": "Google location code (2840 United States, 2826 United Kingdom). Default: the client's project.",
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "description": "Language code (en, es). Default: the client's project.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "CreateReportLinkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          },
          "expiresInDays": {
            "default": 14,
            "type": "integer",
            "minimum": 1,
            "maximum": 90
          },
          "periodDays": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 366
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "RevokeReportLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "reportId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "reportId"
        ],
        "additionalProperties": false
      },
      "ListReportLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "RevokeReportLinkInput": {
        "type": "object",
        "properties": {
          "linkId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "linkId"
        ],
        "additionalProperties": false
      },
      "GetReportDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "The period's first day (UTC)."
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "description": "The period's last day (UTC), inclusive."
          },
          "compareTo": {
            "default": "previous_period",
            "type": "string",
            "enum": [
              "previous_period",
              "previous_year"
            ]
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "GetBudgetStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetScheduledWorkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateLeadWidgetInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "heading": {
            "type": "string",
            "minLength": 1,
            "maxLength": 140
          },
          "accentColor": {
            "type": "string",
            "pattern": "^#[0-9a-fA-F]{3,8}$",
            "description": "The button colour, as hex."
          },
          "allowedOrigins": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 200,
              "format": "uri"
            },
            "description": "Sites allowed to show the form, as origins (https://agency.example). Empty allows any site, for testing."
          },
          "notifyEmails": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 254,
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            },
            "description": "Who is emailed when a lead arrives. Empty keeps leads without telling anyone."
          }
        },
        "required": [
          "name"
        ],
        "additionalProperties": false
      },
      "ListLeadWidgetsInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "UpdateLeadWidgetInput": {
        "type": "object",
        "properties": {
          "widgetId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "heading": {
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 140
              },
              {
                "type": "null"
              }
            ]
          },
          "accentColor": {
            "anyOf": [
              {
                "type": "string",
                "pattern": "^#[0-9a-fA-F]{3,8}$",
                "description": "The button colour, as hex."
              },
              {
                "type": "null"
              }
            ]
          },
          "allowedOrigins": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 200,
              "format": "uri"
            },
            "description": "Sites allowed to show the form, as origins (https://agency.example). Empty allows any site, for testing."
          },
          "notifyEmails": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 254,
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            },
            "description": "Who is emailed when a lead arrives. Empty keeps leads without telling anyone."
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "widgetId"
        ],
        "additionalProperties": false
      },
      "ListLeadsInput": {
        "type": "object",
        "properties": {
          "widgetId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "additionalProperties": false
      },
      "GetBingSearchStatsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "dimension": {
            "default": "query",
            "type": "string",
            "enum": [
              "query",
              "page"
            ]
          },
          "query": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "page": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBingCrawlHealthInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBingInboundLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "page": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetBingKeywordResearchInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "country": {
            "type": "string",
            "pattern": "^[a-zA-Z]{2}$"
          },
          "language": {
            "default": "en-US",
            "type": "string",
            "pattern": "^[a-z]{2}(-[A-Za-z]{2})?$"
          },
          "from": {
            "default": null,
            "description": "Default: 90 days before to.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "to": {
            "default": null,
            "description": "Default: today.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "AddBingSiteInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "VerifyBingSiteInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SubmitBingUrlsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2048,
              "format": "uri"
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "InspectBingUrlInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "SubmitBingSitemapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sitemapUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          }
        },
        "required": [
          "clientId",
          "sitemapUrl"
        ],
        "additionalProperties": false
      },
      "VerifyYandexHostInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "method": {
            "default": "file",
            "type": "string",
            "enum": [
              "file",
              "meta",
              "dns"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetYandexIndexingInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 50000
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "GetYandexExternalLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "offset": {
            "default": 0,
            "type": "integer",
            "minimum": 0,
            "maximum": 100000
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetYandexDiagnosticsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetYandexImportantPagesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetYandexQueryHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "device": {
            "default": "ALL",
            "type": "string",
            "enum": [
              "ALL",
              "DESKTOP",
              "MOBILE_AND_TABLET",
              "MOBILE",
              "TABLET"
            ]
          },
          "queryId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "from",
          "to"
        ],
        "additionalProperties": false
      },
      "GetNaverKeywordVolumesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "includeRelated": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "GetEngineCapabilitiesInput": {
        "type": "object",
        "properties": {
          "engines": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "google",
                    "bing",
                    "youtube",
                    "amazon",
                    "yandex",
                    "baidu",
                    "naver",
                    "duckduckgo",
                    "yahoo",
                    "seznam",
                    "app_store",
                    "google_play"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "capabilities": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "rank_tracking",
                    "live_serp",
                    "search_volume",
                    "keyword_difficulty",
                    "keyword_ideas",
                    "ranked_keywords",
                    "top_pages",
                    "content_profile",
                    "serp_features",
                    "serp_history",
                    "webmaster_data",
                    "url_submission"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "GetShareOfSearchInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "topic": {
            "default": null,
            "description": "Keywords containing this text, and AI questions about it.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "keywords": {
            "default": [],
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetEngineKeywordIdeasInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "engine": {
            "type": "string",
            "enum": [
              "bing",
              "amazon"
            ]
          },
          "seeds": {
            "minItems": 1,
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "engine",
          "seeds"
        ],
        "additionalProperties": false
      },
      "GetAppMetricsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "engine": {
            "type": "string",
            "enum": [
              "app_store",
              "google_play"
            ]
          },
          "appIds": {
            "minItems": 1,
            "maxItems": 1000,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "engine",
          "appIds"
        ],
        "additionalProperties": false
      },
      "GetCtrOutliersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Days of Search Console history, ending on the newest day Google has finished.",
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "minImpressions": {
            "default": 100,
            "type": "integer",
            "minimum": 20,
            "maximum": 1000000
          },
          "sigma": {
            "default": 2,
            "type": "number",
            "minimum": 1,
            "maximum": 5
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetQueryIntentsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Days of Search Console history, ending on the newest day Google has finished.",
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "by": {
            "default": "intent",
            "type": "string",
            "enum": [
              "intent",
              "topic"
            ]
          },
          "brand": {
            "default": "all",
            "type": "string",
            "enum": [
              "all",
              "branded",
              "non_branded"
            ]
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSearchAnomaliesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "lookbackDays": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 90
          },
          "scopes": {
            "default": [
              "site",
              "section",
              "topic"
            ],
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "site",
                "section",
                "topic"
              ]
            }
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ForecastSearchClicksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "horizonDays": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 180
          },
          "trends": {
            "default": null,
            "anyOf": [
              {
                "maxItems": 1000,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "minLength": 7,
                      "maxLength": 30
                    },
                    "value": {
                      "type": "number",
                      "minimum": 0
                    }
                  },
                  "required": [
                    "date",
                    "value"
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "scenario": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetZeroClickEstimatesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 28,
            "description": "Days of Search Console history, ending on the newest day Google has finished.",
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPageIndexingReasonsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "template": {
            "default": null,
            "description": "A template as the report writes it, e.g. /products/*.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "reason": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "indexed",
                  "noindex",
                  "blocked_by_robots",
                  "not_found",
                  "server_error",
                  "redirect",
                  "soft_404",
                  "access_denied",
                  "canonical_elsewhere",
                  "duplicate_without_canonical",
                  "crawled_not_indexed",
                  "discovered_not_indexed",
                  "unknown_to_google",
                  "inspection_failed",
                  "not_inspected",
                  "other"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetVolumeCalibrationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSerpIntentShiftsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 14,
            "type": "integer",
            "minimum": 1,
            "maximum": 90
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetQuestionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 7,
            "maximum": 400
          },
          "status": {
            "default": "all",
            "type": "string",
            "enum": [
              "all",
              "unanswered",
              "answered",
              "mentioned"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSerpNewcomersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 7,
            "type": "integer",
            "minimum": 1,
            "maximum": 31
          },
          "baselineWeeks": {
            "default": 4,
            "type": "integer",
            "minimum": 1,
            "maximum": 12
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetLongTailCandidatesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 90,
            "description": "Days of Search Console history, ending on the newest day Google has finished.",
            "type": "integer",
            "minimum": 7,
            "maximum": 480
          },
          "minImpressions": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100000
          },
          "limit": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetLinkVelocityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "domains": {
            "default": [],
            "description": "Default: the client's site and its tracked competitors.",
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 7,
            "maximum": 180
          },
          "baselineDays": {
            "default": 28,
            "type": "integer",
            "minimum": 7,
            "maximum": 180
          },
          "graceDays": {
            "default": 14,
            "type": "integer",
            "minimum": 3,
            "maximum": 60
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetToxicLinkRiskInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "moneyTerms": {
            "default": [],
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "spamScores": {
            "default": {},
            "description": "Domain → DataForSEO spam score, from get_backlink_spam_scores.",
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {
              "type": "number",
              "minimum": 0,
              "maximum": 100
            }
          },
          "fetchSpamScores": {
            "default": false,
            "description": "True to buy the vendor's spam score for every linking site inside this call (one paid request of up to 1,000 sites, the price of get_backlink_spam_scores; sites scored in the last 30 days are reused free). Quote it with estimate_cost or dryRun first.",
            "type": "boolean"
          },
          "minVerdict": {
            "default": "review",
            "type": "string",
            "enum": [
              "review",
              "toxic"
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SaveDisavowFileInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "entries": {
            "minItems": 1,
            "maxItems": 5000,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sourceDomain": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 253
                },
                "scope": {
                  "type": "string",
                  "enum": [
                    "domain",
                    "url"
                  ]
                },
                "url": {
                  "type": "string",
                  "maxLength": 2048
                }
              },
              "required": [
                "sourceDomain",
                "scope"
              ]
            }
          }
        },
        "required": [
          "clientId",
          "entries"
        ],
        "additionalProperties": false
      },
      "GetDisavowHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetReferringNetworksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "target": {
            "default": null,
            "description": "Default: the client's site.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 253
              },
              {
                "type": "null"
              }
            ]
          },
          "type": {
            "default": "subnet",
            "type": "string",
            "enum": [
              "ip",
              "subnet"
            ]
          },
          "limit": {
            "default": 100,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetOutreachMailboxesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateOutreachSequenceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "steps": {
            "minItems": 1,
            "maxItems": 6,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "delayDays": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 60
                },
                "subject": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "body": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 5000
                }
              },
              "required": [
                "delayDays",
                "subject",
                "body"
              ]
            }
          }
        },
        "required": [
          "clientId",
          "name",
          "steps"
        ],
        "additionalProperties": false
      },
      "ListOutreachSequencesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SendOutreachInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "mailboxId": {
            "type": "string",
            "minLength": 1
          },
          "sequenceId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "prospects": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "prospectId": {
                  "type": "string",
                  "minLength": 1
                },
                "to": {
                  "type": "string",
                  "maxLength": 320,
                  "format": "email",
                  "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                },
                "subject": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "body": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 5000
                }
              },
              "required": [
                "prospectId"
              ]
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "mailboxId",
          "prospects"
        ],
        "additionalProperties": false
      },
      "SyncOutreachInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetOutreachStatusInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AuditMerchantFeedInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "merchantId": {
            "default": null,
            "description": "Default: the account the consent opened, or the first of several.",
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d+$"
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 1000,
            "type": "integer",
            "minimum": 1,
            "maximum": 5000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ValidateProductSchemaInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "default": [],
            "maxItems": 25,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "limit": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 25
          },
          "eu": {
            "default": false,
            "description": "Sold in the EU: require the energy efficiency class EPREL asks for.",
            "type": "boolean"
          },
          "render": {
            "default": "auto",
            "type": "string",
            "enum": [
              "off",
              "auto"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckShoppingSerpInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keywords"
        ],
        "additionalProperties": false
      },
      "GetShoppingSerpInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "tasks": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "keyword": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "taskId": {
                  "type": "string",
                  "minLength": 8,
                  "maxLength": 64
                }
              },
              "required": [
                "keyword",
                "taskId"
              ]
            }
          },
          "sellers": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          }
        },
        "required": [
          "clientId",
          "tasks"
        ],
        "additionalProperties": false
      },
      "AuditProductPageInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "manufacturerText": {
            "default": null,
            "description": "The manufacturer's own description, to check the page is not a copy.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 50,
                "maxLength": 20000
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetShoppingKeywordGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keywords": {
            "default": [],
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 200
            }
          },
          "sellers": {
            "default": [],
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          "organicTop": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "days": {
            "default": 90,
            "type": "integer",
            "minimum": 1,
            "maximum": 365
          },
          "limit": {
            "default": 500,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ScoreAmazonListingInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "asin": {
            "type": "string",
            "pattern": "^[A-Z0-9]{10}$"
          },
          "keyword": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en_US",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "competitors": {
            "default": 10,
            "type": "integer",
            "minimum": 3,
            "maximum": 20
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "asin",
          "keyword"
        ],
        "additionalProperties": false
      },
      "ScoreAppMetadataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "store": {
            "type": "string",
            "enum": [
              "app_store",
              "google_play"
            ]
          },
          "appId": {
            "type": "string",
            "minLength": 3,
            "maxLength": 200,
            "description": "App Store: the numeric id (id123456789 or 123456789). Google Play: the package name."
          },
          "keywords": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "taskId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "store",
          "appId"
        ],
        "additionalProperties": false
      },
      "GetAppKeywordGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "store": {
            "type": "string",
            "enum": [
              "app_store",
              "google_play"
            ]
          },
          "appId": {
            "type": "string",
            "minLength": 3,
            "maxLength": 200,
            "description": "App Store: the numeric id (id123456789 or 123456789). Google Play: the package name."
          },
          "competitors": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 200
            }
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 10,
            "maximum": 1000
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "store",
          "appId"
        ],
        "additionalProperties": false
      },
      "MineAppReviewsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "store": {
            "type": "string",
            "enum": [
              "app_store",
              "google_play"
            ]
          },
          "appId": {
            "type": "string",
            "minLength": 3,
            "maxLength": 200,
            "description": "App Store: the numeric id (id123456789 or 123456789). Google Play: the package name."
          },
          "locationCode": {
            "default": 2840,
            "type": "integer",
            "exclusiveMinimum": 0,
            "maximum": 9007199254740991
          },
          "languageCode": {
            "default": "en",
            "type": "string",
            "minLength": 2,
            "maxLength": 8
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 20,
            "maximum": 500
          },
          "taskId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "store",
          "appId"
        ],
        "additionalProperties": false
      },
      "YoutubeKeywordResearchInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "seed": {
            "type": "string",
            "minLength": 2,
            "maxLength": 100
          },
          "measure": {
            "default": 5,
            "type": "integer",
            "minimum": 0,
            "maximum": 10
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "seed"
        ],
        "additionalProperties": false
      },
      "YoutubeVideoBriefInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200
          },
          "videos": {
            "default": 5,
            "type": "integer",
            "minimum": 3,
            "maximum": 10
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "GetYoutubeChannelRankingsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "channel": {
            "type": "string",
            "minLength": 2,
            "maxLength": 200,
            "description": "A channel id (UC…) or the channel's name."
          },
          "keywords": {
            "minItems": 1,
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 2,
              "maxLength": 200
            }
          },
          "depth": {
            "default": 40,
            "type": "integer",
            "minimum": 10,
            "maximum": 100
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "exclusiveMinimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "channel",
          "keywords"
        ],
        "additionalProperties": false
      },
      "GetSeoChangesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "againstCrawlId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "fields": {
            "default": [],
            "maxItems": 12,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "status",
                "robots",
                "title",
                "canonical",
                "hreflang",
                "h1",
                "schema",
                "description",
                "og",
                "h2",
                "body",
                "performance"
              ]
            }
          },
          "severity": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "critical",
                  "warning",
                  "notice"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "template": {
            "default": null,
            "description": "A template from byTemplate, e.g. /blog/*, to see only its pages.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 300
              },
              {
                "type": "null"
              }
            ]
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CheckDeployInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "previewUrl": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "urls": {
            "default": [],
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "maxUrls": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "failOn": {
            "default": "critical",
            "type": "string",
            "enum": [
              "critical",
              "warning",
              "notice"
            ]
          },
          "baselineCrawlId": {
            "default": null,
            "description": "A complete crawl of this client to compare with, from list_crawls; default the latest complete one.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CompareSitesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "a": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri",
            "description": "The site under test, e.g. staging."
          },
          "b": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri",
            "description": "The reference, e.g. production."
          },
          "paths": {
            "default": [],
            "maxItems": 200,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 2000
            }
          },
          "maxPages": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "sendCrawlAuthTo": {
            "default": "a",
            "type": "string",
            "enum": [
              "a",
              "b",
              "none"
            ]
          },
          "followRedirect": {
            "default": false,
            "description": "When one side's home redirects to the other's host, follow it and check each path lands on the same path there, instead of stopping.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "a",
          "b"
        ],
        "additionalProperties": false
      },
      "GetRobotsHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "TestRobotsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "minItems": 1,
            "maxItems": 50,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "bots": {
            "default": [],
            "maxItems": 40,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 60
            }
          }
        },
        "required": [
          "clientId",
          "urls"
        ],
        "additionalProperties": false
      },
      "ValidateSitemapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "checkFiles": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ExportSitemapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CapturePageScreenshotsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "viewports": {
            "default": [
              "1920x1080",
              "1366x768",
              "768x1024",
              "375x812"
            ],
            "minItems": 1,
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "1920x1080",
                "1366x768",
                "768x1024",
                "375x812"
              ]
            }
          },
          "parity": {
            "default": true,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "GetImageSerpInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "keyword": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "locationCode": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": -9007199254740991,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "languageCode": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 8
              },
              {
                "type": "null"
              }
            ]
          },
          "device": {
            "default": "desktop",
            "type": "string",
            "enum": [
              "desktop",
              "mobile"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "keyword"
        ],
        "additionalProperties": false
      },
      "ValidateStructuredDataInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetHreflangReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetTranslationGapInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "examples": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetMediaReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          },
          "checkSizes": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSecurityReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetVitalsHistoryInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "formFactor": {
            "default": "phone",
            "type": "string",
            "enum": [
              "phone",
              "desktop",
              "all"
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSiteConventionsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          },
          "samples": {
            "default": 8,
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPreloadReadinessInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2000,
                "format": "uri"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ConnectLogSourceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "kind": {
            "type": "string",
            "enum": [
              "cloudflare-logpush",
              "cloudflare-worker",
              "vercel",
              "fastly",
              "s3",
              "upload"
            ]
          },
          "label": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 80
              },
              {
                "type": "null"
              }
            ]
          },
          "s3": {
            "default": null,
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "bucket": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 63
                  },
                  "prefix": {
                    "default": "",
                    "type": "string",
                    "maxLength": 500
                  },
                  "region": {
                    "default": "us-east-1",
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 40
                  },
                  "endpoint": {
                    "default": null,
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 500,
                        "format": "uri"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "accessKeyId": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 200
                  },
                  "secretAccessKey": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 200
                  }
                },
                "required": [
                  "bucket",
                  "accessKeyId",
                  "secretAccessKey"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "vercelVerify": {
            "default": null,
            "description": "The verification value Vercel shows when adding the drain, echoed back as x-vercel-verify.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "kind"
        ],
        "additionalProperties": false
      },
      "ListLogSourcesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RevokeLogSourceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "sourceId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "sourceId"
        ],
        "additionalProperties": false
      },
      "GetCrawlBudgetInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "bot": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 2,
                "maxLength": 40
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetAiCrawlerActivityInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetLogOrphansInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "days": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "limit": {
            "default": 200,
            "type": "integer",
            "minimum": 1,
            "maximum": 1000
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "IssueServerCollectKeyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "CreateGoalInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "kind": {
            "type": "string",
            "enum": [
              "pageview",
              "event"
            ]
          },
          "match": {
            "type": "string",
            "minLength": 1,
            "maxLength": 300,
            "description": "A path for a pageview (\"/thanks\", \"/signup/*\"; * matches anything) or an event name."
          },
          "valueMinor": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 9007199254740991
              },
              {
                "type": "null"
              }
            ]
          },
          "upsertBy": {
            "description": "With \"name\": a goal of that name already defined the same way is returned as it is (created: false), and one defined differently is replaced, so a provisioning script can run this every time.",
            "type": "string",
            "enum": [
              "name"
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "name",
          "kind",
          "match"
        ],
        "additionalProperties": false
      },
      "ListGoalsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DeleteGoalInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "goalId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "goalId"
        ],
        "additionalProperties": false
      },
      "CreateFunnelInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "steps": {
            "minItems": 2,
            "maxItems": 8,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "pageview",
                    "event"
                  ]
                },
                "match": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 300,
                  "description": "A path for a pageview (\"/thanks\", \"/signup/*\"; * matches anything) or an event name."
                },
                "label": {
                  "type": "string",
                  "maxLength": 100
                }
              },
              "required": [
                "kind",
                "match"
              ]
            }
          },
          "upsertBy": {
            "description": "With \"name\": a funnel of that name with the same steps is returned as it is (created: false), and one with different steps is replaced.",
            "type": "string",
            "enum": [
              "name"
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "name",
          "steps"
        ],
        "additionalProperties": false
      },
      "ListFunnelsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DeleteFunnelInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "funnelId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "funnelId"
        ],
        "additionalProperties": false
      },
      "GetGoalReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "goalIds": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "by": {
            "default": "channel",
            "description": "channel (AI assistants, organic search, paid, social, email, referral, direct), landing_page, source, campaign, ai_referrer (which assistant sent the visit), query_cluster (the Search Console queries bringing people to each landing page), or none.",
            "type": "string",
            "enum": [
              "none",
              "channel",
              "landing_page",
              "source",
              "campaign",
              "ai_referrer",
              "query_cluster"
            ]
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetFunnelReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "funnelId": {
            "type": "string",
            "minLength": 1
          },
          "by": {
            "default": "none",
            "description": "channel (AI assistants, organic search, paid, social, email, referral, direct), landing_page, source, campaign, ai_referrer (which assistant sent the visit), query_cluster (the Search Console queries bringing people to each landing page), or none.",
            "type": "string",
            "enum": [
              "none",
              "channel",
              "landing_page",
              "source",
              "campaign",
              "ai_referrer",
              "query_cluster"
            ]
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "limit": {
            "default": 20,
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        },
        "required": [
          "clientId",
          "funnelId"
        ],
        "additionalProperties": false
      },
      "GetAiAgentVisitsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "by": {
            "default": "agent",
            "type": "string",
            "enum": [
              "agent",
              "operator",
              "page",
              "day"
            ]
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 400
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ConnectRevenueSourceInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "shopify",
              "paddle"
            ]
          },
          "apiKey": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "shop": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 3,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "accessToken": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 8,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "sandbox": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "ImportRevenueNowInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "stripe",
                  "shopify",
                  "paddle"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSeoRevenueInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "by": {
            "default": "channel",
            "type": "string",
            "enum": [
              "channel",
              "landing_page",
              "query_cluster",
              "campaign",
              "source",
              "ai_referrer",
              "provider"
            ]
          },
          "days": {
            "default": 28,
            "type": "integer",
            "minimum": 1,
            "maximum": 730
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 250
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "RecordOrderInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "orderId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "amountMinor": {
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000000
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Za-z]{3}$"
          },
          "at": {
            "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)))$"
          },
          "visit": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 128
              },
              {
                "type": "null"
              }
            ]
          },
          "refundOf": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "customerId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "orderId",
          "amountMinor",
          "currency",
          "at"
        ],
        "additionalProperties": false
      },
      "RecordOrdersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "orders": {
            "minItems": 1,
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "orderId": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "amountMinor": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 1000000000000
                },
                "currency": {
                  "type": "string",
                  "pattern": "^[A-Za-z]{3}$"
                },
                "at": {
                  "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)))$"
                },
                "visit": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 128
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "refundOf": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                "customerId": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 200
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "orderId",
                "amountMinor",
                "currency",
                "at"
              ]
            }
          }
        },
        "required": [
          "clientId",
          "orders"
        ],
        "additionalProperties": false
      },
      "ConnectIntegrationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "airtable",
              "slack",
              "discord",
              "telegram",
              "jira",
              "linear",
              "github",
              "matomo"
            ]
          },
          "token": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "webhookUrl": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "channel": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "chatId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ]
          },
          "site": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "email": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "projectKey": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ]
          },
          "issueType": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 60
              },
              {
                "type": "null"
              }
            ]
          },
          "teamId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "owner": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "repo": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "idSite": {
            "default": null,
            "description": "For Matomo: the site's id (idSite).",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 12
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "ListIntegrationsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DisconnectIntegrationInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "shopify",
              "paddle",
              "google_sheets",
              "bigquery",
              "airtable",
              "slack",
              "discord",
              "telegram",
              "jira",
              "linear",
              "github",
              "matomo"
            ]
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "GetIntegrationConnectLinkInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "shopify",
              "slack",
              "linear",
              "google_sheets",
              "bigquery"
            ]
          },
          "shop": {
            "default": null,
            "description": "For Shopify: the store's myshopify.com domain.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "teamId": {
            "default": null,
            "description": "For Linear: the team issues are filed in.",
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "CreateDataSyncInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "destination": {
            "type": "string",
            "enum": [
              "google_sheets",
              "airtable",
              "bigquery"
            ]
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "query": {
            "type": "object",
            "properties": {
              "dataset": {
                "type": "string",
                "enum": [
                  "gsc",
                  "web_events",
                  "crawl_pages",
                  "crawl_issues",
                  "crawl_links",
                  "rank_captures",
                  "backlinks",
                  "revenue_orders",
                  "web_agent_visits"
                ]
              },
              "dimensions": {
                "default": [],
                "maxItems": 6,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "metrics": {
                "default": [],
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "columns": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "filters": {
                "default": [],
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "column": {
                      "type": "string",
                      "minLength": 1
                    },
                    "op": {
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "contains",
                        "not_contains",
                        "starts_with",
                        "gt",
                        "gte",
                        "lt",
                        "lte",
                        "in",
                        "regex"
                      ]
                    },
                    "value": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "array",
                          "items": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "number"
                              }
                            ]
                          }
                        }
                      ]
                    }
                  },
                  "required": [
                    "column",
                    "op",
                    "value"
                  ]
                }
              },
              "from": {
                "default": null,
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 30
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "to": {
                "default": null,
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 30
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "orderBy": {
                "default": [],
                "maxItems": 4,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "field": {
                      "type": "string",
                      "minLength": 1
                    },
                    "desc": {
                      "default": true,
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "field"
                  ]
                }
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000000
              },
              "crawlId": {
                "default": "latest",
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "dataset"
            ],
            "description": "The same query query_data takes, without clientId: see describe_datasets."
          },
          "mode": {
            "default": "replace",
            "type": "string",
            "enum": [
              "append",
              "replace"
            ]
          },
          "windowDays": {
            "default": null,
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 400
              },
              {
                "type": "null"
              }
            ]
          },
          "cadence": {
            "default": "daily",
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "runHour": {
            "default": 6,
            "type": "integer",
            "minimum": 0,
            "maximum": 23
          },
          "spreadsheetId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "sheet": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "baseId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "table": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "projectId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          },
          "datasetId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 1024
              },
              {
                "type": "null"
              }
            ]
          },
          "tableId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 1024
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "destination",
          "name",
          "query"
        ],
        "additionalProperties": false
      },
      "ListDataSyncsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "UpdateDataSyncInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "syncId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "query": {
            "type": "object",
            "properties": {
              "dataset": {
                "type": "string",
                "enum": [
                  "gsc",
                  "web_events",
                  "crawl_pages",
                  "crawl_issues",
                  "crawl_links",
                  "rank_captures",
                  "backlinks",
                  "revenue_orders",
                  "web_agent_visits"
                ]
              },
              "dimensions": {
                "default": [],
                "maxItems": 6,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "metrics": {
                "default": [],
                "maxItems": 10,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "columns": {
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              "filters": {
                "default": [],
                "maxItems": 20,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "column": {
                      "type": "string",
                      "minLength": 1
                    },
                    "op": {
                      "type": "string",
                      "enum": [
                        "eq",
                        "neq",
                        "contains",
                        "not_contains",
                        "starts_with",
                        "gt",
                        "gte",
                        "lt",
                        "lte",
                        "in",
                        "regex"
                      ]
                    },
                    "value": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "number"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "array",
                          "items": {
                            "anyOf": [
                              {
                                "type": "string"
                              },
                              {
                                "type": "number"
                              }
                            ]
                          }
                        }
                      ]
                    }
                  },
                  "required": [
                    "column",
                    "op",
                    "value"
                  ]
                }
              },
              "from": {
                "default": null,
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 30
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "to": {
                "default": null,
                "anyOf": [
                  {
                    "type": "string",
                    "minLength": 10,
                    "maxLength": 30
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "orderBy": {
                "default": [],
                "maxItems": 4,
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "field": {
                      "type": "string",
                      "minLength": 1
                    },
                    "desc": {
                      "default": true,
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "field"
                  ]
                }
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 1000000
              },
              "crawlId": {
                "default": "latest",
                "type": "string",
                "minLength": 1
              }
            },
            "required": [
              "dataset"
            ],
            "description": "The same query query_data takes, without clientId: see describe_datasets."
          },
          "mode": {
            "type": "string",
            "enum": [
              "append",
              "replace"
            ]
          },
          "windowDays": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1,
                "maximum": 400
              },
              {
                "type": "null"
              }
            ]
          },
          "cadence": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "runHour": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23
          },
          "paused": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "syncId"
        ],
        "additionalProperties": false
      },
      "DeleteDataSyncInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "syncId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "syncId"
        ],
        "additionalProperties": false
      },
      "RunDataSyncNowInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "syncId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "syncId"
        ],
        "additionalProperties": false
      },
      "PreviewWeeklyDigestInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ScheduleWeeklyDigestInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "slack",
              "discord",
              "telegram"
            ]
          },
          "weekday": {
            "default": 1,
            "type": "integer",
            "minimum": 0,
            "maximum": 6
          },
          "runHour": {
            "default": 8,
            "type": "integer",
            "minimum": 0,
            "maximum": 23
          },
          "paused": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "ListDigestSchedulesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DeleteDigestScheduleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "digestId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId",
          "digestId"
        ],
        "additionalProperties": false
      },
      "SendWeeklyDigestNowInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "slack",
              "discord",
              "telegram"
            ]
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "PushTasksToTrackerInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "provider": {
            "type": "string",
            "enum": [
              "jira",
              "linear",
              "github"
            ]
          },
          "taskIds": {
            "default": null,
            "anyOf": [
              {
                "minItems": 1,
                "maxItems": 200,
                "type": "array",
                "items": {
                  "type": "string",
                  "minLength": 1
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "statuses": {
            "default": [
              "todo",
              "in_progress"
            ],
            "minItems": 1,
            "maxItems": 4,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "todo",
                "in_progress",
                "done",
                "wont_do"
              ]
            }
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "provider"
        ],
        "additionalProperties": false
      },
      "SyncTaskStatusesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListTaskLinksInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetSeoScorecardInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "crawlId": {
            "default": "latest",
            "description": "A crawl id from list_crawls, or \"latest\" for the newest complete one.",
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AuditPageInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "render": {
            "default": "auto",
            "type": "string",
            "enum": [
              "off",
              "auto"
            ]
          },
          "pageType": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "home",
                  "service",
                  "location_primary",
                  "location_secondary",
                  "blog",
                  "product",
                  "category",
                  "about",
                  "landing",
                  "faq",
                  "other"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "url"
        ],
        "additionalProperties": false
      },
      "ScoreEeatInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "urls": {
            "default": [],
            "maxItems": 20,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2000,
              "format": "uri"
            }
          },
          "topPages": {
            "default": 10,
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          },
          "judge": {
            "default": false,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "DraftSeoStrategyInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "competitors": {
            "default": [],
            "maxItems": 5,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 3,
              "maxLength": 253
            }
          },
          "instructions": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 4000
              },
              {
                "type": "null"
              }
            ]
          },
          "save": {
            "default": true,
            "type": "boolean"
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetMatomoReportInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "report": {
            "default": "overview",
            "type": "string",
            "enum": [
              "overview",
              "channels",
              "landing_pages",
              "pages",
              "goals"
            ]
          },
          "channel": {
            "default": "all",
            "description": "organic: visits from search engines; ai: from AI assistants (Matomo 5.3+); all: every channel.",
            "type": "string",
            "enum": [
              "all",
              "organic",
              "ai"
            ]
          },
          "from": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "to": {
            "type": "string",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
          },
          "compare": {
            "default": true,
            "type": "boolean"
          },
          "limit": {
            "default": 25,
            "type": "integer",
            "minimum": 1,
            "maximum": 500
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "AddDefaultAlertsInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "allClients": {
            "type": "boolean"
          },
          "channel": {
            "type": "string",
            "enum": [
              "slack",
              "webhook",
              "discord",
              "email",
              "telegram"
            ]
          },
          "webhookUrl": {
            "type": "string",
            "maxLength": 2048,
            "format": "uri"
          },
          "emailRecipients": {
            "maxItems": 10,
            "type": "array",
            "items": {
              "type": "string",
              "format": "email",
              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
            }
          },
          "telegramChatId": {
            "type": "string",
            "minLength": 2,
            "maxLength": 64
          },
          "include": {
            "maxItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "page-changes"
              ]
            }
          }
        },
        "additionalProperties": false
      },
      "SetCrawlScheduleInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "cadence": {
            "type": "string",
            "enum": [
              "off",
              "daily",
              "weekly",
              "monthly"
            ]
          },
          "day": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 28
              },
              {
                "type": "null"
              }
            ]
          },
          "hour": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0,
                "maximum": 23
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId",
          "cadence"
        ],
        "additionalProperties": false
      },
      "AcceptIssueInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ruleId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "template": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 500
              },
              {
                "type": "null"
              }
            ]
          },
          "urls": {
            "default": [],
            "maxItems": 500,
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 2048,
              "format": "uri"
            }
          },
          "reason": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000
          },
          "until": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
              },
              {
                "type": "null"
              }
            ]
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "ruleId",
          "reason"
        ],
        "additionalProperties": false
      },
      "ListAcceptedIssuesInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "includeLapsed": {
            "default": false,
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "UnacceptIssueInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "ids": {
            "minItems": 1,
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          }
        },
        "required": [
          "clientId",
          "ids"
        ],
        "additionalProperties": false
      },
      "SetPathOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "owners": {
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "prefix": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 500,
                  "pattern": "^\\/"
                },
                "owner": {
                  "type": "string",
                  "minLength": 1,
                  "maxLength": 200
                },
                "contact": {
                  "default": null,
                  "anyOf": [
                    {
                      "type": "string",
                      "maxLength": 300
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              },
              "required": [
                "prefix",
                "owner"
              ]
            }
          },
          "mode": {
            "default": "replace",
            "description": "replace: owners is the whole list. merge: owners are added or updated, remove is dropped, the rest kept.",
            "type": "string",
            "enum": [
              "replace",
              "merge"
            ]
          },
          "remove": {
            "default": [],
            "description": "Prefixes to drop, with mode merge.",
            "maxItems": 100,
            "type": "array",
            "items": {
              "type": "string",
              "minLength": 1,
              "maxLength": 500,
              "pattern": "^\\/"
            }
          },
          "dryRun": {
            "default": false,
            "description": "True to do nothing and get back exactly what the call would do: the rows it would write, the addresses it would submit, the emails it would send.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "ListPathOwnersInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetVendorReconciliationInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "EstimateCostInput": {
        "type": "object",
        "properties": {
          "tool": {
            "type": "string",
            "minLength": 1
          },
          "arguments": {
            "default": {},
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          }
        },
        "required": [
          "tool"
        ],
        "additionalProperties": false
      },
      "FindToolsInput": {
        "type": "object",
        "properties": {
          "task": {
            "type": "string",
            "minLength": 3,
            "maxLength": 500
          },
          "limit": {
            "default": 8,
            "type": "integer",
            "minimum": 1,
            "maximum": 20
          }
        },
        "required": [
          "task"
        ],
        "additionalProperties": false
      },
      "GetRecipeInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "name": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "weekly_review",
                  "new_article",
                  "technical_audit",
                  "site_migration",
                  "competitor_teardown",
                  "ai_visibility_baseline"
                ]
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "GetPriceListInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "SetBudgetInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "monthlyUsd": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 1000000
              },
              {
                "type": "null"
              }
            ]
          },
          "alertAt": {
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0,
                "maximum": 1
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "clientId"
        ],
        "additionalProperties": false
      },
      "SetDomainSweepInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "enabled"
        ],
        "additionalProperties": false
      },
      "GetJobInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "jobId": {
            "type": "string",
            "pattern": "^(crawl|rank|domain|performance):[A-Za-z0-9_.:-]{1,200}$"
          }
        },
        "required": [
          "clientId",
          "jobId"
        ],
        "additionalProperties": false
      },
      "WaitForJobInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "jobId": {
            "type": "string",
            "pattern": "^(crawl|rank|domain|performance):[A-Za-z0-9_.:-]{1,200}$"
          },
          "timeoutSeconds": {
            "default": 30,
            "type": "integer",
            "minimum": 1,
            "maximum": 60
          }
        },
        "required": [
          "clientId",
          "jobId"
        ],
        "additionalProperties": false
      },
      "CreateWebhookInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1
              },
              {
                "type": "null"
              }
            ]
          },
          "url": {
            "type": "string",
            "maxLength": 2000,
            "format": "uri"
          },
          "events": {
            "minItems": 1,
            "maxItems": 13,
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "crawl.completed",
                "gsc.synced",
                "rank.moved",
                "backlink.new",
                "backlink.lost",
                "issue.new_critical",
                "ai.citation.gained",
                "ai.citation.lost",
                "competitor.page.new",
                "budget.threshold",
                "alert.fired",
                "vendor.balance_low",
                "vendor.balance_empty"
              ]
            }
          }
        },
        "required": [
          "url",
          "events"
        ],
        "additionalProperties": false
      },
      "ListWebhooksInput": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "DeleteWebhookInput": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "webhookId"
        ],
        "additionalProperties": false
      },
      "ListWebhookDeliveriesInput": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "limit": {
            "default": 50,
            "type": "integer",
            "minimum": 1,
            "maximum": 200
          }
        },
        "required": [
          "webhookId"
        ],
        "additionalProperties": false
      },
      "ReplayWebhooksInput": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "since": {
            "default": null,
            "anyOf": [
              {
                "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)))$"
              },
              {
                "type": "null"
              }
            ]
          },
          "deliveryId": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "webhookId"
        ],
        "additionalProperties": false
      },
      "SendTestEventInput": {
        "type": "object",
        "properties": {
          "webhookId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "webhookId"
        ],
        "additionalProperties": false
      },
      "GetErrorCatalogueInput": {
        "type": "object",
        "properties": {
          "code": {
            "default": null,
            "anyOf": [
              {
                "type": "string",
                "minLength": 1,
                "maxLength": 100
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "ExplainResultInput": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string",
            "minLength": 1
          },
          "tool": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "result": {},
          "audience": {
            "default": "client",
            "type": "string",
            "enum": [
              "client",
              "team"
            ]
          },
          "maxCostMicros": {
            "description": "Optional spending limit for this call, in micro-USD (1,000,000 = $1). The call is checked against its quote first and refused with nothing bought (meta.costMicros 0) when the quote is over it; should purchases cost more than quoted, the call stops at the limit and meta.costMicros says what was already bought. Pass the estimate from estimate_cost, or what the user agreed to spend.",
            "type": "integer",
            "minimum": 0,
            "maximum": 1000000000
          },
          "dryRun": {
            "description": "True to buy nothing and get the quote instead: what the call would cost at most and what it would buy.",
            "type": "boolean"
          }
        },
        "required": [
          "clientId",
          "tool",
          "result"
        ],
        "additionalProperties": false
      }
    }
  }
}