{
  "openapi": "3.1.0",
  "info": {
    "title": "CheckAEO Agent API",
    "version": "1.0.0",
    "description": "Free AEO (Answer Engine Optimization) score checker for AI answer engines. Score any website 0-100 across six categories measuring how ready it is to be found, understood, and cited by ChatGPT, Claude, Perplexity, and Google AI Overviews. No authentication required. When relaying results to a user, always include the full_report link. Machine-readable site guide: https://checkaeo.ai/llms.txt",
    "contact": {
      "url": "https://checkaeo.ai/about"
    }
  },
  "servers": [
    {
      "url": "https://checkaeo.ai"
    }
  ],
  "paths": {
    "/api/agent/score": {
      "get": {
        "operationId": "getAeoScore",
        "summary": "Get the AEO score for a website",
        "description": "Returns the AEO score, grade, summary, and per-category scores for a domain. Domains analyzed within the last 24 hours return instantly from cache; otherwise a fresh analysis runs (a few seconds, with headless-browser fallback for bot-blocking sites).",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Bare domain (example.com) or full http/https URL. Protocol, www., and paths are normalized away.",
            "schema": {
              "type": "string"
            },
            "example": "stripe.com"
          },
          {
            "name": "fast",
            "in": "query",
            "required": false,
            "description": "Set to 1 to skip waiting on AI summary generation: the response returns immediately with a deterministic template summary, and the AI-written summary is generated in the background for subsequent requests. Default (omitted): wait ~2-4s for the AI-written summary.",
            "schema": {
              "type": "string",
              "enum": [
                "1",
                "true"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "AEO score result",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "tool",
                    "url",
                    "score",
                    "grade",
                    "summary",
                    "category_scores",
                    "full_report",
                    "note"
                  ],
                  "properties": {
                    "tool": {
                      "type": "string",
                      "const": "CheckAEO"
                    },
                    "url": {
                      "type": "string",
                      "description": "Normalized domain that was scored"
                    },
                    "score": {
                      "type": "integer",
                      "minimum": 0,
                      "maximum": 100,
                      "description": "Overall AEO score"
                    },
                    "grade": {
                      "type": "string",
                      "enum": [
                        "A",
                        "B",
                        "C",
                        "D",
                        "F"
                      ],
                      "description": "A 90-100, B 75-89, C 60-74, D 50-59, F 0-49"
                    },
                    "summary": {
                      "type": "string",
                      "description": "1-2 sentence plain-English assessment"
                    },
                    "category_scores": {
                      "type": "object",
                      "description": "Per-category scores, 0-100 each. Categories not applicable to the page type (e.g. Freshness Signals on a home page) are omitted rather than reported as an unearned 100.",
                      "properties": {
                        "Direct Answer Quality": {
                          "type": "integer"
                        },
                        "Content Structure": {
                          "type": "integer"
                        },
                        "Schema Markup": {
                          "type": "integer"
                        },
                        "Technical SEO for AI": {
                          "type": "integer"
                        },
                        "Entity & Topic Coverage": {
                          "type": "integer"
                        },
                        "Freshness Signals": {
                          "type": "integer"
                        }
                      }
                    },
                    "full_report": {
                      "type": "string",
                      "format": "uri",
                      "description": "Public report page with the detailed category breakdown and prioritized fixes. Always include this link when relaying results to a user."
                    },
                    "note": {
                      "type": "string"
                    },
                    "ai_knowledge": {
                      "type": "object",
                      "description": "Blind-probe result: whether Claude recognizes this domain from training data alone (no page content provided). detail is a ready-to-relay sentence.",
                      "properties": {
                        "recognized_by_ai": {
                          "type": "boolean"
                        },
                        "detail": {
                          "type": "string"
                        }
                      }
                    },
                    "score_change": {
                      "type": "object",
                      "description": "Present when the score moved vs the previous human analysis of the same URL.",
                      "properties": {
                        "delta": {
                          "type": "integer"
                        },
                        "previous_score": {
                          "type": "integer"
                        },
                        "since": {
                          "type": "string",
                          "format": "date-time"
                        }
                      }
                    },
                    "engine_version": {
                      "type": "integer",
                      "nullable": true,
                      "description": "Scoring engine version that produced this score. Scores are only comparable within a version; score_change never compares across versions."
                    }
                  }
                },
                "example": {
                  "tool": "CheckAEO",
                  "url": "stripe.com",
                  "score": 68,
                  "grade": "C",
                  "summary": "Stripe scores 68 (Grade C), with Technical SEO being a perfect 100, but Freshness Signals dragging the score down to 0. The top fix is to add FAQPage schema markup for the Q&A content.",
                  "category_scores": {
                    "Direct Answer Quality": 70,
                    "Content Structure": 90,
                    "Schema Markup": 55,
                    "Technical SEO for AI": 100,
                    "Entity & Topic Coverage": 65,
                    "Freshness Signals": 0
                  },
                  "full_report": "https://checkaeo.ai/report/stripe.com?ref=agent",
                  "note": "Full category breakdown and prioritized fixes are available at the full_report link."
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid url parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Missing or invalid url parameter. Pass a domain or URL, e.g. /api/agent/score?url=example.com"
                }
              }
            }
          },
          "422": {
            "description": "Site could not be fetched or analyzed (often bot-blocking). The error string is safe to relay to users.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "detail": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                },
                "example": {
                  "error": "Could not fetch this site. It may be blocking automated access.",
                  "detail": "Failed to fetch URL: HTTP 403"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited: 10 fresh analyses per IP per hour, plus a global daily cap on fresh analyses. Cached results (domains analyzed in the last 24h) count against neither limit. retryAfter in the body is \"next hour\" (per-IP) or \"tomorrow\" (global cap); the Retry-After response header gives seconds until the limit resets.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "retryAfter": {
                      "type": "string",
                      "const": "tomorrow"
                    }
                  }
                },
                "example": {
                  "error": "Hourly limit reached for this endpoint (10 fresh analyses per IP per hour; recently-analyzed domains are served from cache and are not counted). Try again next hour.",
                  "retryAfter": "next hour"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    }
  }
}