{
  "openapi": "3.1.0",
  "info": {
    "title": "ChimpanSEO API",
    "version": "1.0.0",
    "description": "ChimpanSEO writes SEO and GEO articles and publishes them to WordPress. Agents act on a user's account through the MCP endpoint (POST /api/mcp, JSON-RPC over Streamable HTTP, API key required). A few public endpoints run the free GEO audit without an account. Full MCP tool list: https://chimpanseo.app/.well-known/mcp.json Versioning: the API is versioned in the URL path (/api/v1). The unversioned paths (/api/mcp, /api/public/audit) remain as aliases of v1; a breaking change would ship as /api/v2 with v1 kept for at least 6 months. Every response carries an API-Version header. The audit endpoint returns a RateLimit-Policy header (5 audits per IP per hour) and Retry-After on 429.",
    "contact": {
      "email": "hello@chimpanseo.app",
      "url": "https://chimpanseo.app/contact"
    }
  },
  "servers": [
    {
      "url": "https://chimpanseo.app"
    }
  ],
  "externalDocs": {
    "description": "MCP documentation",
    "url": "https://chimpanseo.app/mcp"
  },
  "tags": [
    {
      "name": "mcp",
      "description": "Model Context Protocol endpoint"
    },
    {
      "name": "audit",
      "description": "Free public GEO audit"
    }
  ],
  "paths": {
    "/api/v1/mcp": {
      "post": {
        "operationId": "mcpJsonRpc",
        "tags": [
          "mcp"
        ],
        "summary": "Call the ChimpanSEO MCP server",
        "description": "Single JSON-RPC 2.0 endpoint of the remote MCP server (Streamable HTTP, stateless). initialize, ping, tools/list, resources/list and prompts/list work without a key. tools/call needs an API key created in the dashboard (Settings, API/MCP), sent as Bearer token or x-api-key header. Tools: list_sites, generate_article, get_generation_status, get_article, list_articles, publish_article, schedule_article, list_scheduled_articles, cancel_scheduled_article, refresh_article, suggest_topics, audit_site, get_usage.",
        "security": [
          {},
          {
            "bearerApiKey": []
          },
          {
            "headerApiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/list"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (result or error).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key for a method that needs one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many failed key attempts; wait and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/public/audit": {
      "post": {
        "operationId": "startPublicAudit",
        "tags": [
          "audit"
        ],
        "summary": "Start a free GEO audit of a public URL",
        "description": "Runs the free audit on a public website and returns a partial report. The full report is unlocked by email confirmation (see unlockPublicAudit). Rate limited per IP and globally.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public http(s) URL to audit."
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "it",
                      "en"
                    ],
                    "description": "Language of the report."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Audit started; includes the report id and the free part of the report.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "url": {
                      "type": "string"
                    },
                    "score": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 100
                    },
                    "seoScore": {
                      "type": "integer"
                    },
                    "aiScore": {
                      "type": "integer"
                    },
                    "grade": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "unlockedChecks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "lockedChecks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "label": {
                            "type": "string"
                          },
                          "maxPoints": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "lockedCount": {
                      "type": "integer"
                    },
                    "topFixesCount": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "id",
                    "url",
                    "score"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or non-public URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Audit could not be completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/public/audit/{id}/unlock": {
      "post": {
        "operationId": "unlockPublicAudit",
        "tags": [
          "audit"
        ],
        "summary": "Request the full audit report by email",
        "description": "Sends a confirmation email to the given address. The full report is sent after the recipient confirms the link.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "it",
                      "en"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Confirmation email sent.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid email or request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Report not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited. Honour the Retry-After header.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Email could not be delivered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/public/audit/{id}/status": {
      "get": {
        "operationId": "getPublicAuditStatus",
        "tags": [
          "audit"
        ],
        "summary": "Check whether the audit email has been confirmed",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmation state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "confirmed": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "confirmed"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Unknown report id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "confirmed": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from the dashboard (Settings, API/MCP), sent as 'Authorization: Bearer <key>'. Keys act on the owner's account within plan limits."
      },
      "headerApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Same API key, sent as x-api-key header."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable code (present on unknown-route errors)."
          },
          "resolution": {
            "type": "string",
            "description": "What to do next."
          },
          "status": {
            "type": "integer"
          },
          "title": {
            "type": "string"
          },
          "detail": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "documentation_url": {
            "type": "string"
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer",
              "null"
            ]
          },
          "method": {
            "type": "string",
            "description": "For example initialize, tools/list, tools/call."
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer",
              "null"
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}