{
  "openapi": "3.1.0",
  "info": {
    "title": "LLMSE API",
    "version": "1.1.0",
    "description": "REST API for LLMSE website classification and analysis. Provides AI-powered URL classification, SEO analysis, E-E-A-T evaluation, AEO (Answer Engine Optimization) scoring, readability analysis, WCAG accessibility checks, GARM brand safety scoring, AI disclosure compliance, comprehensive audits, advertiser matching, and similar site discovery.\n\nAll endpoints are public with per-domain rate limiting (1 request per domain per 60 seconds). Cached results are returned instantly without consuming rate limits. Authenticated users (via Bearer token) receive the same rate limits with future support for higher tiers.\n\nRate limit status is returned in response headers:\n- `X-RateLimit-Limit`: Maximum requests per window per domain\n- `X-RateLimit-Remaining`: Requests remaining in current window\n- `X-RateLimit-Reset`: Unix timestamp when the window resets\n- `Retry-After`: Seconds until next request is allowed (429 responses only)",
    "contact": {
      "name": "LLMSE",
      "url": "https://llmse.ai"
    }
  },
  "servers": [
    {
      "url": "https://llmse.ai",
      "description": "Production"
    }
  ],
  "security": [
    {},
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Descope JWT token. Optional — all endpoints work without authentication."
      }
    },
    "parameters": {
      "url": {
        "name": "url",
        "in": "query",
        "required": true,
        "description": "The website URL to analyze",
        "schema": {
          "type": "string",
          "format": "uri"
        },
        "example": "https://example.com"
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum requests allowed per window per domain",
        "schema": {
          "type": "integer",
          "example": 1
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in current window",
        "schema": {
          "type": "integer",
          "example": 1
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp when the rate limit window resets",
        "schema": {
          "type": "integer",
          "example": 1740200000
        }
      },
      "Retry-After": {
        "description": "Seconds until next request is allowed (429 responses only)",
        "schema": {
          "type": "integer",
          "example": 45
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          }
        },
        "required": ["error"]
      },
      "FetchError": {
        "type": "object",
        "description": "Error returned when HTML fetch fails",
        "properties": {
          "url": {
            "type": "string"
          },
          "error": {
            "type": "string",
            "description": "Error message (e.g., 'Request timed out', 'Could not connect', 'HTTP error: 404', 'Not HTML content: application/pdf', 'Too many redirects')"
          },
          "cached": {
            "type": "boolean",
            "const": false
          }
        },
        "required": ["url", "error", "cached"]
      },
      "RateLimitError": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "error": {
            "type": "string",
            "example": "Rate limited. Try again in 45 seconds."
          },
          "rate_limited": {
            "type": "boolean",
            "const": true
          },
          "retry_after": {
            "type": "integer",
            "description": "Seconds until next request is allowed"
          }
        },
        "required": ["error", "rate_limited", "retry_after"]
      },
      "Issue": {
        "type": "object",
        "description": "A single analysis issue with code, message, and impact",
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable issue code (e.g., 'SEO_NO_TITLE', 'EEAT_NO_AUTHOR')",
            "example": "SEO_NO_TITLE"
          },
          "message": {
            "type": "string",
            "description": "Human-readable issue description",
            "example": "Page has no title tag"
          },
          "impact": {
            "type": "string",
            "description": "Impact level of the issue",
            "example": "high"
          }
        },
        "required": ["code", "message", "impact"]
      },
      "CategorizedIssues": {
        "type": "object",
        "description": "Issues grouped by severity level",
        "properties": {
          "critical": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "info": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        },
        "required": ["critical", "warnings", "info"]
      },
      "ClassifyResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "The normalized URL"
          },
          "cached": {
            "type": "boolean",
            "description": "Whether result was from cache"
          },
          "category": {
            "type": "string",
            "description": "Main category (e.g., Sports, Technology)",
            "example": "Technology"
          },
          "subcategory": {
            "type": "string",
            "description": "Specific subcategory",
            "example": "Software Development"
          },
          "language": {
            "type": "string",
            "description": "Detected content language",
            "example": "English"
          },
          "sentiment": {
            "type": "string",
            "enum": ["Good", "Neutral", "Bad"],
            "description": "Content sentiment"
          },
          "age": {
            "type": "string",
            "description": "Target age group (present only if detected)",
            "example": "25-34"
          },
          "gender": {
            "type": "string",
            "description": "Target gender (present only if detected)",
            "example": "all"
          },
          "server": {
            "type": "string",
            "description": "Detected web server (present only if detected)"
          },
          "app": {
            "type": "string",
            "description": "Detected web application/CMS (present only if detected)"
          },
          "seo_grade": {
            "type": "string",
            "description": "SEO grade A-F (present only if previously analyzed)",
            "example": "B"
          },
          "eeat_grade": {
            "type": "string",
            "description": "E-E-A-T grade A-F (present only if previously analyzed)",
            "example": "C"
          },
          "aeo_grade": {
            "type": "string",
            "description": "AEO grade A-F (present only if previously analyzed)"
          },
          "readability_grade": {
            "type": "string",
            "description": "Readability grade A-F (present only if previously analyzed)",
            "example": "B"
          },
          "wcag_grade": {
            "type": "string",
            "description": "WCAG 2.1 accessibility grade A-F (present only if previously analyzed)",
            "example": "B"
          },
          "garm_grade": {
            "type": "string",
            "description": "GARM brand safety grade A-F (present only if previously analyzed)",
            "example": "A"
          },
          "ai_disclosure_grade": {
            "type": "string",
            "description": "AI Disclosure grade A-F (present only if previously analyzed)",
            "example": "A"
          },
          "privacy_grade": {
            "type": "string",
            "description": "Privacy Compliance grade A-F (present only if previously analyzed)",
            "example": "A"
          }
        },
        "required": ["url", "cached", "category", "subcategory", "language", "sentiment"]
      },
      "SEOResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "SEO score (0-100). Deduction-based: starts at 100, subtracts per issue (critical -15, warning -5, info -1).",
            "minimum": 0,
            "maximum": 100
          },
          "grade": {
            "type": "string",
            "description": "Letter grade. Thresholds: A>=90, B>=80, C>=70, D>=60, F<60.",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "meta": {
            "type": "object",
            "description": "Extracted SEO metadata from HTML analysis",
            "properties": {
              "title": {
                "type": "string"
              },
              "title_length": {
                "type": "integer"
              },
              "description": {
                "type": "string"
              },
              "description_length": {
                "type": "integer"
              },
              "h1_count": {
                "type": "integer"
              },
              "heading_count": {
                "type": "integer"
              },
              "heading_hierarchy": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "has_viewport": {
                "type": "boolean"
              },
              "has_canonical": {
                "type": "boolean"
              },
              "canonical_url": {
                "type": "string"
              },
              "has_lang": {
                "type": "boolean"
              },
              "lang": {
                "type": "string"
              },
              "has_charset": {
                "type": "boolean"
              },
              "has_noindex": {
                "type": "boolean"
              },
              "has_nofollow": {
                "type": "boolean"
              },
              "total_images": {
                "type": "integer"
              },
              "images_without_alt": {
                "type": "integer"
              },
              "images_with_empty_alt": {
                "type": "integer"
              },
              "has_og_title": {
                "type": "boolean"
              },
              "has_og_description": {
                "type": "boolean"
              },
              "has_og_image": {
                "type": "boolean"
              },
              "has_twitter_card": {
                "type": "boolean"
              },
              "has_schema": {
                "type": "boolean"
              },
              "schema_types": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "word_count": {
                "type": "integer"
              },
              "internal_links": {
                "type": "integer"
              },
              "external_links": {
                "type": "integer"
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Prioritized list of improvements"
          }
        },
        "required": ["score", "grade", "issues", "meta", "recommendations"]
      },
      "EEATResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "Overall EEAT score (0-100). Weighted average: experience 15%, expertise 25%, authoritativeness 25%, trustworthiness 35%."
          },
          "grade": {
            "type": "string",
            "description": "Letter grade. Thresholds: A>=90, B>=80, C>=70, D>=60, F<60.",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "scores": {
            "type": "object",
            "description": "Individual EEAT category scores (0-100 each)",
            "properties": {
              "experience": {
                "type": "integer"
              },
              "expertise": {
                "type": "integer"
              },
              "authoritativeness": {
                "type": "integer"
              },
              "trustworthiness": {
                "type": "integer"
              }
            },
            "required": ["experience", "expertise", "authoritativeness", "trustworthiness"]
          },
          "issues": {
            "type": "object",
            "description": "Issues categorized by EEAT component (NOT by severity). Each component contains an array of Issue objects.",
            "properties": {
              "experience": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "expertise": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "authoritativeness": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "trustworthiness": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "content_quality": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "technical": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              },
              "ymyl": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Issue"
                }
              }
            }
          },
          "signals": {
            "type": "object",
            "description": "Detected positive EEAT signals by category",
            "properties": {
              "experience": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "expertise": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "authoritativeness": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "trustworthiness": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "meta": {
            "type": "object",
            "description": "EEAT metadata",
            "properties": {
              "content_type": {
                "type": "string",
                "description": "Detected content type (e.g., article, product, page)"
              },
              "ymyl_type": {
                "type": ["string", "null"],
                "description": "YMYL category if detected (health, financial, legal)"
              },
              "is_ymyl": {
                "type": "boolean"
              },
              "is_article": {
                "type": "boolean"
              },
              "is_product": {
                "type": "boolean"
              },
              "schema_types": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["score", "grade", "scores", "issues", "signals", "meta", "recommendations"]
      },
      "AEOMetricScore": {
        "type": "object",
        "description": "Individual AEO metric score with details",
        "properties": {
          "score": {
            "type": "integer",
            "description": "Points earned for this metric"
          },
          "max_score": {
            "type": "integer",
            "description": "Maximum possible points for this metric"
          }
        },
        "required": ["score", "max_score"]
      },
      "AEOResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "aeo_score": {
            "type": "integer",
            "description": "Overall AEO score (0-100). Additive across 10 metrics with clickbait penalty up to -10."
          },
          "aeo_grade": {
            "type": "string",
            "description": "Letter grade. Thresholds: A>=85, B>=70, C>=55, D>=40, F<40.",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "aeo_metrics": {
            "type": "object",
            "description": "Individual AEO metric scores across 10 categories totaling 100 points",
            "properties": {
              "answer_format": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 15
                  },
                  "qa_pairs_count": {
                    "type": "integer"
                  },
                  "signals": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "faq_schema": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 12
                  },
                  "has_schema": {
                    "type": "boolean"
                  },
                  "has_content": {
                    "type": "boolean"
                  },
                  "is_valid": {
                    "type": ["boolean", "null"]
                  }
                }
              },
              "howto_schema": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 8
                  },
                  "has_schema": {
                    "type": "boolean"
                  },
                  "has_content": {
                    "type": "boolean"
                  },
                  "is_valid": {
                    "type": ["boolean", "null"]
                  }
                }
              },
              "direct_snippets": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 11
                  },
                  "snippet_count": {
                    "type": "integer"
                  },
                  "avg_length": {
                    "type": "number"
                  },
                  "max_length": {
                    "type": "integer"
                  }
                }
              },
              "entity_clarity": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 9
                  },
                  "definitions_count": {
                    "type": "integer"
                  },
                  "avg_length": {
                    "type": "number"
                  },
                  "has_glossary": {
                    "type": "boolean"
                  }
                }
              },
              "source_citations": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 13
                  },
                  "citation_count": {
                    "type": "integer"
                  },
                  "by_type": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "integer"
                    }
                  },
                  "signals": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "statistics": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 10
                  },
                  "statistics_count": {
                    "type": "integer"
                  },
                  "by_type": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "integer"
                    }
                  },
                  "signals": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "schema_completeness": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 10
                  },
                  "has_organization_schema": {
                    "type": "boolean"
                  },
                  "has_article_schema": {
                    "type": "boolean"
                  },
                  "has_author_schema": {
                    "type": "boolean"
                  },
                  "is_article_page": {
                    "type": "boolean"
                  },
                  "schema_types_count": {
                    "type": "integer"
                  }
                }
              },
              "content_freshness": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 6
                  },
                  "signal_count": {
                    "type": "integer"
                  },
                  "by_type": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "integer"
                    }
                  }
                }
              },
              "topical_authority": {
                "type": "object",
                "properties": {
                  "score": {
                    "type": "integer"
                  },
                  "max_score": {
                    "type": "integer",
                    "example": 6
                  },
                  "word_count": {
                    "type": "integer"
                  },
                  "heading_count": {
                    "type": "integer"
                  },
                  "internal_links": {
                    "type": "integer"
                  },
                  "external_links": {
                    "type": "integer"
                  },
                  "has_table_of_contents": {
                    "type": "boolean"
                  }
                }
              },
              "clickbait_penalty": {
                "type": "object",
                "properties": {
                  "penalty": {
                    "type": "integer",
                    "description": "Points deducted (0 to -10)",
                    "minimum": -10,
                    "maximum": 0
                  },
                  "detected_count": {
                    "type": "integer"
                  },
                  "patterns": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "citation": {
            "type": "object",
            "description": "Full Citation Readiness analysis nested within AEO",
            "properties": {
              "score": {
                "type": "integer",
                "description": "Citation readiness score (0-100)"
              },
              "grade": {
                "type": "string",
                "enum": ["A", "B", "C", "D", "F"]
              },
              "category_scores": {
                "type": "object",
                "properties": {
                  "structure": {
                    "type": "integer"
                  },
                  "schema": {
                    "type": "integer"
                  },
                  "content": {
                    "type": "integer"
                  },
                  "freshness": {
                    "type": "integer"
                  },
                  "technical": {
                    "type": "integer"
                  }
                }
              },
              "issues": {
                "$ref": "#/components/schemas/CategorizedIssues"
              },
              "signals": {
                "type": "object",
                "description": "Citation signals by category",
                "properties": {
                  "structure": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "schema": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "content": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "freshness": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "technical": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "recommendations": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "meta": {
                "type": "object"
              }
            }
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "signals": {
            "type": "object",
            "description": "Detected AEO signals",
            "properties": {
              "qa_patterns": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "question": {
                      "type": "string"
                    },
                    "source": {
                      "type": "string"
                    }
                  }
                }
              },
              "direct_snippets": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "words": {
                      "type": "integer"
                    },
                    "source": {
                      "type": "string"
                    }
                  }
                }
              },
              "entity_definitions": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "term": {
                      "type": "string"
                    },
                    "pattern": {
                      "type": "string"
                    }
                  }
                }
              },
              "source_citations": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "source": {
                      "type": "string"
                    }
                  }
                }
              },
              "statistics": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    }
                  }
                }
              },
              "summary_blocks_count": {
                "type": "integer"
              },
              "has_faq_content": {
                "type": "boolean"
              },
              "has_howto_content": {
                "type": "boolean"
              },
              "has_glossary": {
                "type": "boolean"
              },
              "has_organization_schema": {
                "type": "boolean"
              },
              "has_article_schema": {
                "type": "boolean"
              },
              "has_author_schema": {
                "type": "boolean"
              },
              "is_article_page": {
                "type": "boolean"
              },
              "clickbait_signals": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "pattern": {
                      "type": "string"
                    }
                  }
                }
              },
              "freshness_signals": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    }
                  }
                }
              },
              "topical_authority": {
                "type": ["object", "null"],
                "properties": {
                  "word_count": {
                    "type": "integer"
                  },
                  "heading_count": {
                    "type": "integer"
                  },
                  "internal_links": {
                    "type": "integer"
                  },
                  "external_links": {
                    "type": "integer"
                  },
                  "has_table_of_contents": {
                    "type": "boolean"
                  }
                }
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "agent_readiness": {
            "type": "object",
            "description": "AI agent readiness signals (llms.txt, robots.txt, SSR detection, WebMCP)",
            "properties": {
              "llms_txt": {
                "type": "object",
                "properties": {
                  "present": {
                    "type": "boolean"
                  },
                  "valid": {
                    "type": "boolean"
                  },
                  "issues": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "llms_full_txt": {
                "type": "object",
                "properties": {
                  "present": {
                    "type": "boolean"
                  }
                }
              },
              "robots_txt": {
                "type": "object",
                "properties": {
                  "ai_policies": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "crawlers_blocked": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "crawlers_allowed": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "crawlers_unknown": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "rendering": {
                "type": "object",
                "properties": {
                  "is_server_rendered": {
                    "type": "boolean"
                  },
                  "signals": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "webmcp": {
                "type": "object",
                "properties": {
                  "is_ready": {
                    "type": "boolean"
                  },
                  "signals": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "required": ["aeo_score", "aeo_grade", "aeo_metrics", "citation", "issues", "signals", "recommendations", "agent_readiness"]
      },
      "ReadabilityResult": {
        "type": "object",
        "description": "Content readability analysis using Flesch Reading Ease. Grade thresholds: A>=60 (easy/web-friendly), B>=50, C>=30, D>=10, F<10.",
        "properties": {
          "url": {
            "type": "string",
            "description": "The analyzed URL"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "number",
            "description": "Flesch Reading Ease score (0-100, higher = easier). Rounded to 1 decimal place."
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "flesch_kincaid_grade_level": {
            "type": "number",
            "description": "US school grade level equivalent. Rounded to 1 decimal place."
          },
          "reading_time_minutes": {
            "type": "number",
            "description": "Estimated reading time in minutes"
          },
          "word_count": {
            "type": "integer",
            "description": "Total word count"
          },
          "sentence_count": {
            "type": "integer",
            "description": "Total sentence count"
          },
          "difficult_words": {
            "type": "integer",
            "description": "Count of difficult/uncommon words"
          }
        },
        "required": ["score", "grade", "flesch_kincaid_grade_level", "reading_time_minutes", "word_count", "sentence_count", "difficult_words"]
      },
      "GARMResult": {
        "type": "object",
        "description": "GARM Brand Suitability Framework analysis. Grade thresholds: A>=80, B>=60, C>=40, D>=20, F<20. Higher score = safer for advertising.",
        "properties": {
          "url": {
            "type": ["string", "null"],
            "description": "The analyzed URL, or null if category was provided directly"
          },
          "category": {
            "type": "string",
            "description": "LLMSE content category used for GARM mapping"
          },
          "sentiment": {
            "type": "string",
            "enum": ["Bad", "Neutral", "Good"],
            "description": "Content sentiment used for score adjustment"
          },
          "score": {
            "type": "integer",
            "description": "Brand safety score (0-100, higher = safer)"
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "garm_category": {
            "type": ["string", "null"],
            "description": "Matched GARM category name, or null if brand-safe"
          },
          "risk_level": {
            "type": "string",
            "enum": ["none", "low", "medium", "high", "floor"],
            "description": "GARM risk level"
          },
          "is_floor": {
            "type": "boolean",
            "description": "Whether this category is not suitable for any advertising"
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": ["score", "grade", "garm_category", "risk_level", "is_floor", "issues", "recommendations"]
      },
      "WCAGResult": {
        "type": "object",
        "description": "WCAG 2.1 Level A accessibility analysis. Automated static HTML checks cover approximately 30-40% of WCAG 2.1 Level A criteria. Grade thresholds: A>=90, B>=80, C>=70, D>=60, F<60.",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "Accessibility score (0-100)"
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "meta": {
            "type": "object",
            "description": "Accessibility metadata",
            "properties": {
              "images_total": {
                "type": "integer"
              },
              "images_missing_alt": {
                "type": "integer"
              },
              "inputs_total": {
                "type": "integer"
              },
              "inputs_missing_label": {
                "type": "integer"
              },
              "heading_count": {
                "type": "integer"
              },
              "heading_skips": {
                "type": "integer"
              },
              "has_page_title": {
                "type": "boolean"
              },
              "html_lang": {
                "type": "string"
              },
              "links_total": {
                "type": "integer"
              },
              "links_empty": {
                "type": "integer"
              },
              "buttons_total": {
                "type": "integer"
              },
              "buttons_empty": {
                "type": "integer"
              },
              "aria_role_elements": {
                "type": "integer"
              },
              "aria_missing_names": {
                "type": "integer"
              },
              "duplicate_ids": {
                "type": "integer"
              },
              "has_skip_nav": {
                "type": "boolean"
              },
              "tables_total": {
                "type": "integer"
              },
              "tables_missing_headers": {
                "type": "integer"
              },
              "has_landmarks": {
                "type": "boolean"
              },
              "landmarks": {
                "type": "object",
                "properties": {
                  "main": {
                    "type": "boolean"
                  },
                  "nav": {
                    "type": "boolean"
                  },
                  "header": {
                    "type": "boolean"
                  },
                  "footer": {
                    "type": "boolean"
                  }
                }
              },
              "viewport_blocks_zoom": {
                "type": "boolean"
              },
              "media_total": {
                "type": "integer"
              },
              "media_autoplay": {
                "type": "integer"
              },
              "positive_tabindex": {
                "type": "integer"
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "coverage_note": {
            "type": "string",
            "description": "Disclaimer about automated coverage limitations"
          }
        },
        "required": ["score", "grade", "issues", "meta", "recommendations", "coverage_note"]
      },
      "AIDisclosureResult": {
        "type": "object",
        "description": "AI Disclosure compliance analysis for EU AI Act readiness. All checks are conditional — issues only raised when AI/chatbot technology is detected. Non-AI sites score 100/A. Grade thresholds: A>=90, B>=80, C>=70, D>=60, F<60.",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "AI Disclosure score (0-100). Deduction-based: chatbot unlabeled -15, no disclosure -5, no policy -5, vague disclosure -1.",
            "minimum": 0,
            "maximum": 100
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "meta": {
            "type": "object",
            "description": "Detected AI disclosure metadata",
            "properties": {
              "has_explicit_disclosure": {
                "type": "boolean",
                "description": "Strong AI disclosure statement found (e.g., 'AI-generated', 'powered by AI')"
              },
              "has_vague_disclosure": {
                "type": "boolean",
                "description": "Weaker disclosure language found (e.g., 'AI assistance', 'machine-generated')"
              },
              "has_policy_link": {
                "type": "boolean",
                "description": "Link to AI usage policy page found"
              },
              "has_chatbot_tech": {
                "type": "boolean",
                "description": "Chatbot/AI technology detected (e.g., Intercom, Drift, ChatGPT Widget)"
              },
              "has_chatbot_label": {
                "type": "boolean",
                "description": "AI attribution found on chatbot widget (aria-label, title, or visible text)"
              },
              "detected_chatbot_apps": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Names of detected chatbot/AI technologies"
              },
              "disclosure_texts": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Matched disclosure text snippets (up to 120 chars each)"
              },
              "policy_urls": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "URLs of detected AI policy pages"
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "signals": {
            "type": "object",
            "description": "Summary of detected positive signals",
            "properties": {
              "disclosure": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "policy_links": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "chatbot_apps": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": ["score", "grade", "issues", "meta", "recommendations", "signals"]
      },
      "PrivacyResult": {
        "type": "object",
        "description": "Privacy compliance analysis evaluating cookie consent, policy links, tracker scripts, and CCPA signals. Grade thresholds: A>=90, B>=80, C>=70, D>=60, F<60.",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "Privacy compliance score (0-100). Deduction-based: no consent banner -15, no privacy policy -15, no cookie policy -5, no do-not-sell -5, excessive trackers -5, scripts not consent-gated -1, no data processing text -1.",
            "minimum": 0,
            "maximum": 100
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "issues": {
            "$ref": "#/components/schemas/CategorizedIssues"
          },
          "meta": {
            "type": "object",
            "description": "Detected privacy compliance metadata",
            "properties": {
              "has_consent_banner": {
                "type": "boolean",
                "description": "Cookie consent banner or CMP detected"
              },
              "has_privacy_policy": {
                "type": "boolean",
                "description": "Privacy policy link found"
              },
              "has_cookie_policy": {
                "type": "boolean",
                "description": "Separate cookie policy link found"
              },
              "has_do_not_sell": {
                "type": "boolean",
                "description": "CCPA 'Do Not Sell' or 'Do Not Share' link found"
              },
              "has_consent_gated_scripts": {
                "type": "boolean",
                "description": "Tracker scripts behind consent gate detected"
              },
              "has_data_processing_text": {
                "type": "boolean",
                "description": "Data processing disclosure text found"
              },
              "tracker_count": {
                "type": "integer",
                "description": "Number of third-party tracker scripts detected"
              },
              "tracker_domains": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Domains of detected tracker scripts"
              },
              "consent_banner_type": {
                "type": "string",
                "description": "Type of consent banner detected (CMP domain or 'banner-element')"
              }
            }
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "signals": {
            "type": "object",
            "description": "Summary of detected privacy signals",
            "properties": {
              "consent_banner_type": {
                "type": "string"
              },
              "privacy_policy_urls": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "cookie_policy_urls": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "do_not_sell_urls": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "tracker_domains": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "data_processing_texts": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": ["score", "grade", "issues", "meta", "recommendations", "signals"]
      },
      "Advertiser": {
        "type": "object",
        "description": "An advertiser with targeting preferences",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique advertiser identifier",
            "example": "adv_001"
          },
          "name": {
            "type": "string",
            "description": "Advertiser display name",
            "example": "Nike"
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Target categories"
          },
          "age_groups": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Target age groups"
          },
          "genders": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Target genders"
          },
          "sentiments": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Acceptable sentiment values"
          },
          "bid_cpm": {
            "type": "number",
            "description": "CPM bid amount in dollars"
          },
          "creative_url": {
            "type": "string",
            "description": "URL to ad creative"
          },
          "landing_url": {
            "type": "string",
            "description": "Click destination URL"
          },
          "active": {
            "type": "boolean",
            "description": "Whether advertiser is currently active"
          }
        },
        "required": ["id", "name", "categories", "age_groups", "genders", "sentiments", "bid_cpm", "creative_url", "landing_url", "active"]
      },
      "AdvertiserMatch": {
        "type": "object",
        "description": "A matched advertiser with scoring details",
        "properties": {
          "advertiser": {
            "$ref": "#/components/schemas/Advertiser"
          },
          "score": {
            "type": "number",
            "description": "Total match score (category +10, age +5, gender +3, sentiment +2, CPM tiebreaker)"
          },
          "category_match": {
            "type": "boolean"
          },
          "age_match": {
            "type": "boolean"
          },
          "gender_match": {
            "type": "boolean"
          },
          "sentiment_match": {
            "type": "boolean"
          }
        },
        "required": ["advertiser", "score", "category_match", "age_match", "gender_match", "sentiment_match"]
      },
      "DemographicsInfo": {
        "type": "object",
        "description": "Demographics used for advertiser matching",
        "properties": {
          "category": {
            "type": ["string", "null"]
          },
          "subcategory": {
            "type": ["string", "null"]
          },
          "age": {
            "type": ["string", "null"]
          },
          "gender": {
            "type": ["string", "null"]
          },
          "sentiment": {
            "type": ["string", "null"]
          }
        }
      },
      "AdvertiserResultUrl": {
        "type": "object",
        "description": "Advertiser match result when URL is provided",
        "properties": {
          "url": {
            "type": "string"
          },
          "classification": {
            "$ref": "#/components/schemas/DemographicsInfo"
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdvertiserMatch"
            }
          },
          "match_count": {
            "type": "integer"
          }
        },
        "required": ["url", "classification", "matches", "match_count"]
      },
      "AdvertiserResultDemographics": {
        "type": "object",
        "description": "Advertiser match result when demographics are provided directly",
        "properties": {
          "demographics": {
            "$ref": "#/components/schemas/DemographicsInfo"
          },
          "cpm_filter": {
            "type": "object",
            "properties": {
              "min_cpm": {
                "type": ["number", "null"]
              },
              "max_cpm": {
                "type": ["number", "null"]
              }
            }
          },
          "matches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdvertiserMatch"
            }
          },
          "match_count": {
            "type": "integer"
          }
        },
        "required": ["demographics", "cpm_filter", "matches", "match_count"]
      },
      "SimilarSitesResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "classification": {
            "type": "object",
            "properties": {
              "category": {
                "type": "string"
              },
              "subcategory": {
                "type": "string"
              }
            }
          },
          "similar_sites": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of similar URLs"
          },
          "total_in_category": {
            "type": "integer",
            "description": "Total sites in this category"
          },
          "cached": {
            "type": "boolean"
          }
        },
        "required": ["url", "classification", "similar_sites", "total_in_category", "cached"]
      },
      "WidgetResult": {
        "type": "object",
        "description": "Lightweight SEO check result for embeddable widget",
        "properties": {
          "url": {
            "type": "string"
          },
          "score": {
            "type": "integer",
            "description": "SEO score (0-100)"
          },
          "grade": {
            "type": "string",
            "enum": ["A", "B", "C", "D", "F"]
          },
          "top_issues": {
            "type": "array",
            "description": "Up to 3 top issues, prioritized: critical > warnings > info",
            "maxItems": 3,
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "severity": {
                  "type": "string",
                  "enum": ["critical", "warnings", "info"]
                },
                "message": {
                  "type": "string"
                }
              },
              "required": ["code", "severity", "message"]
            }
          }
        },
        "required": ["url", "score", "grade", "top_issues"]
      },
      "AuditResult": {
        "type": "object",
        "description": "Comprehensive audit combining all analysis types. Fetches the URL once and runs classification, SEO, EEAT, AEO, readability, WCAG, GARM, AI disclosure, advertiser matching, and similar site discovery. Any sub-analysis that fails returns {\"error\": \"...\"} instead of its normal result.",
        "properties": {
          "url": {
            "type": "string"
          },
          "cached": {
            "type": "boolean"
          },
          "classification": {
            "type": "object",
            "properties": {
              "category": {
                "type": "string"
              },
              "subcategory": {
                "type": "string"
              },
              "language": {
                "type": "string"
              },
              "sentiment": {
                "type": "string",
                "enum": ["Good", "Neutral", "Bad"]
              },
              "age": {
                "type": "string",
                "description": "Present only if detected"
              },
              "gender": {
                "type": "string",
                "description": "Present only if detected"
              }
            },
            "required": ["category", "subcategory", "language", "sentiment"]
          },
          "seo": {
            "description": "SEO analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/SEOResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "eeat": {
            "description": "EEAT analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/EEATResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "aeo": {
            "description": "AEO analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AEOResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "readability": {
            "description": "Readability analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/ReadabilityResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "wcag": {
            "description": "WCAG analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/WCAGResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "garm": {
            "description": "GARM analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/GARMResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "ai_disclosure": {
            "description": "AI Disclosure analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/AIDisclosureResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "privacy": {
            "description": "Privacy compliance analysis result, or {\"error\": \"...\"} if analysis failed",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PrivacyResult"
              },
              {
                "$ref": "#/components/schemas/Error"
              }
            ]
          },
          "advertisers": {
            "type": "object",
            "description": "Matched advertisers (up to 3)",
            "properties": {
              "matches": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/AdvertiserMatch"
                }
              },
              "match_count": {
                "type": "integer"
              }
            },
            "required": ["matches", "match_count"]
          },
          "similar_sites": {
            "type": "object",
            "description": "Related sites from the same category (up to 10)",
            "properties": {
              "sites": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "total_in_category": {
                "type": "integer"
              }
            }
          }
        },
        "required": ["url", "cached", "classification", "seo", "eeat", "aeo", "readability", "wcag", "garm", "ai_disclosure", "privacy", "advertisers", "similar_sites"]
      }
    },
    "responses": {
      "RateLimitResponse": {
        "description": "Rate limited",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RateLimitError"
            }
          }
        }
      },
      "SuccessHeaders": {
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/classify": {
      "get": {
        "operationId": "classifyUrl",
        "summary": "Classify a URL",
        "description": "Fetches the URL and uses AI to determine category, subcategory, language, sentiment, and target demographics. Results are cached for fast subsequent lookups. Optional fields (age, gender, server, app, grade fields) are present only if detected or previously analyzed.",
        "tags": ["Classification"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "Classification result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClassifyResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid url parameter",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/seo": {
      "get": {
        "operationId": "analyzeSeo",
        "summary": "Analyze SEO",
        "description": "Analyzes a website for SEO issues including title tags, meta descriptions, headings, images, schema markup, accessibility, performance hints, and more. Returns a score (0-100) and grade (A-F) with prioritized recommendations.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "SEO analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SEOResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/eeat": {
      "get": {
        "operationId": "analyzeEeat",
        "summary": "Analyze E-E-A-T",
        "description": "Evaluates content quality signals based on Google's E-E-A-T framework (Experience, Expertise, Authoritativeness, Trustworthiness). Detects author credentials, organization schema, trust signals, YMYL content, and more. Issues are categorized by EEAT component rather than severity.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "EEAT analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EEATResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/aeo": {
      "get": {
        "operationId": "analyzeAeo",
        "summary": "Analyze AEO",
        "description": "Evaluates how well content is optimized for AI answer engines (ChatGPT, Perplexity, Gemini, Claude). Analyzes Q&A patterns, FAQ/HowTo schema, direct answer snippets, entity clarity, source citations, statistics, and schema completeness. Includes full Citation Readiness analysis, AI agent readiness signals (llms.txt, robots.txt, SSR detection, WebMCP), and clickbait penalty.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "AEO analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AEOResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/wcag": {
      "get": {
        "operationId": "analyzeWcag",
        "summary": "Analyze WCAG Accessibility",
        "description": "Performs automated WCAG 2.1 Level A accessibility analysis with 15 static HTML checks covering images, forms, headings, page title, lang attribute, links, buttons, ARIA, duplicate IDs, skip navigation, tables, landmarks, viewport zoom, autoplay media, and tabindex. Returns score (0-100), A-F grade, categorized issues, metadata, and recommendations. Automated checks cover approximately 30-40% of WCAG 2.1 Level A criteria.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "WCAG accessibility analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WCAGResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/readability": {
      "get": {
        "operationId": "analyzeReadability",
        "summary": "Analyze Readability",
        "description": "Analyzes content readability using Flesch Reading Ease. Returns score (0-100), grade (A-F), Flesch-Kincaid grade level, estimated reading time, and word/sentence statistics. Web content should target grade A (60+ Flesch score) for broad accessibility.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "Readability analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadabilityResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/garm": {
      "get": {
        "operationId": "analyzeGarm",
        "summary": "Analyze GARM Brand Safety",
        "description": "Maps content to the GARM Brand Suitability Framework. Accepts either a URL (classification fetched from cache) or explicit category/sentiment parameters. Returns a brand safety score (0-100, higher = safer), letter grade (A-F), matched GARM category, risk level, and recommendations. Floor categories (e.g., Adult) always score 0/F.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "URL to analyze (classification fetched from cache). Provide either url or category.",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "LLMSE content category (e.g., 'Sports', 'Adult', 'Crime'). Used when url is not provided.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sentiment",
            "in": "query",
            "required": false,
            "description": "Content sentiment. Defaults to 'Neutral' if not provided or invalid.",
            "schema": {
              "type": "string",
              "enum": ["Good", "Neutral", "Bad"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GARM brand safety analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GARMResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing url or category parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/ai-disclosure": {
      "get": {
        "operationId": "analyzeAiDisclosure",
        "summary": "Analyze AI Disclosure",
        "description": "Analyzes a website for AI transparency compliance, detecting AI disclosure statements, AI usage policies, and chatbot labeling. Checks are conditional: issues are only raised when AI or chatbot technology is detected on the page. Sites with no AI footprint score 100/A. Supports EU AI Act readiness assessment. Detects 23 chatbot/AI technologies.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "AI Disclosure analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AIDisclosureResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/privacy": {
      "get": {
        "operationId": "analyzePrivacy",
        "summary": "Analyze Privacy Compliance",
        "description": "Evaluates the visible privacy posture of a web page by checking for cookie consent mechanisms (OneTrust, Cookiebot, CookieYes, Termly, Usercentrics, and more), privacy and cookie policy links, CCPA 'Do Not Sell' links, third-party tracker script enumeration, consent-gated script loading patterns, and data processing disclosure text. Detects 40+ tracker domains and 20+ CMP platforms.",
        "tags": ["Analysis"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "Privacy compliance analysis result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrivacyResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/audit": {
      "get": {
        "operationId": "auditUrl",
        "summary": "Comprehensive audit",
        "description": "Performs a full website audit combining classification, SEO, E-E-A-T, AEO (with Citation Readiness and Agent Readiness), readability, WCAG, GARM, AI disclosure, privacy compliance, advertiser matching, and similar site discovery in a single request. Fetches the page only once. Also fetches /robots.txt, /llms.txt, and /llms-full.txt for AEO agent readiness checks. Individual sub-analyses that fail return {\"error\": \"...\"} instead of their normal result.",
        "tags": ["Audit"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "Full audit result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/FetchError"
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/advertisers": {
      "get": {
        "operationId": "selectAdvertiser",
        "summary": "Match advertisers",
        "description": "Matches advertising networks to website content based on classification demographics. Provide either a URL (classification will be fetched automatically) or demographics directly (category, age, gender, sentiment). At least one of url, category, age, gender, or sentiment must be provided. Scoring weights: category match (+10), age match (+5), gender match (+3), sentiment match (+2), with CPM as tiebreaker.",
        "tags": ["Advertisers"],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "URL to match advertisers for (classification will be fetched)",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Target category (e.g., Sports, Technology)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "subcategory",
            "in": "query",
            "description": "Target subcategory",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "age",
            "in": "query",
            "description": "Target age group (e.g., 18-24, 25-34)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "gender",
            "in": "query",
            "description": "Target gender (male, female, or all)",
            "schema": {
              "type": "string",
              "enum": ["male", "female", "all"]
            }
          },
          {
            "name": "sentiment",
            "in": "query",
            "description": "Content sentiment",
            "schema": {
              "type": "string",
              "enum": ["Good", "Neutral", "Bad"]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Number of advertisers to return (1-10)",
            "schema": {
              "type": "integer",
              "default": 3,
              "minimum": 1,
              "maximum": 10
            }
          },
          {
            "name": "min_cpm",
            "in": "query",
            "description": "Minimum CPM cost filter (inclusive)",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "max_cpm",
            "in": "query",
            "description": "Maximum CPM cost filter (inclusive)",
            "schema": {
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Advertiser matches. Response shape varies: includes 'classification' when URL is provided, or 'demographics' and 'cpm_filter' when demographics are provided directly.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AdvertiserResultUrl"
                    },
                    {
                      "$ref": "#/components/schemas/AdvertiserResultDemographics"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "No filters provided or invalid CPM values",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/similar": {
      "get": {
        "operationId": "findSimilarSites",
        "summary": "Find similar sites",
        "description": "Classifies a URL (or uses cached classification) and returns other websites from the same category and subcategory. Useful for competitive analysis and discovering related content.",
        "tags": ["Discovery"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of similar sites to return",
            "schema": {
              "type": "integer",
              "default": 10,
              "minimum": 1,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Similar sites result",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimilarSitesResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimitResponse"
          }
        }
      }
    },
    "/api/v1/ua": {
      "post": {
        "operationId": "submitUserAgent",
        "summary": "Submit a user agent string",
        "description": "Submit a raw user agent string with a source identifier. The UA is parsed, classified, and stored. Submitted UAs appear on the /market/ua page with source tracking. Rate limited to 1 submission per IP per 10 seconds.",
        "tags": ["User Agent"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["user_agent", "source"],
                "properties": {
                  "user_agent": {
                    "type": "string",
                    "description": "Raw user agent string (5-1000 characters)",
                    "minLength": 5,
                    "maxLength": 1000,
                    "example": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
                  },
                  "source": {
                    "type": "string",
                    "description": "Source identifier for the submission (1-100 characters)",
                    "minLength": 1,
                    "maxLength": 100,
                    "example": "my_analytics_app"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Submission accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": ["ok"]
                    }
                  },
                  "required": ["status"]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (missing or invalid fields)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (1 submission per 10 seconds per IP)",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "retry_after": {
                      "type": "integer",
                      "description": "Seconds until next submission is allowed"
                    }
                  },
                  "required": ["error", "retry_after"]
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/widget": {
      "get": {
        "operationId": "widgetCheck",
        "summary": "SEO Widget Check",
        "description": "Lightweight CORS-enabled SEO check designed for embeddable widgets. Returns a slim payload with score, grade, and up to 3 top issues (prioritized: critical > warnings > info). Supports cross-origin requests via Access-Control-Allow-Origin: *.",
        "tags": ["Widget"],
        "parameters": [
          {
            "$ref": "#/components/parameters/url"
          }
        ],
        "responses": {
          "200": {
            "description": "Widget SEO result",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "example": "*"
                }
              },
              "Access-Control-Allow-Methods": {
                "schema": {
                  "type": "string",
                  "example": "GET, OPTIONS"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WidgetResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "options": {
        "operationId": "widgetPreflight",
        "summary": "Widget CORS Preflight",
        "description": "CORS preflight handler for the widget endpoint.",
        "tags": ["Widget"],
        "responses": {
          "204": {
            "description": "CORS preflight response",
            "headers": {
              "Access-Control-Allow-Origin": {
                "schema": {
                  "type": "string",
                  "example": "*"
                }
              },
              "Access-Control-Allow-Methods": {
                "schema": {
                  "type": "string",
                  "example": "GET, OPTIONS"
                }
              },
              "Access-Control-Allow-Headers": {
                "schema": {
                  "type": "string",
                  "example": "Content-Type"
                }
              }
            }
          }
        }
      }
    }
  }
}
