openapi: 3.0.3
info:
  title: SEO Metadata Micro-API
  version: 1.0.0
  description: |
    Extrae metadata y auditoría SEO on-page de cualquier URL pública:
    title, meta description, Open Graph, Twitter Cards, canonical, idioma,
    encabezados (h1–h6), conteo de enlaces internos/externos, imágenes sin alt,
    conteo de palabras, puntuación SEO (0–100) y lista de problemas accionables.

    Autenticación: envía tu API key en el header `X-API-Key`.
    Rate limit: 60 peticiones/minuto por key (headers X-RateLimit-*).
  contact:
    name: Soporte
    url: https://tu-dominio.vercel.app
servers:
  - url: https://tu-dominio.vercel.app
    description: Producción (Vercel)
security:
  - apiKey: []
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: Tu API key privada.
  schemas:
    Issue:
      type: object
      required: [severity, code, message, fix]
      properties:
        severity: { type: string, enum: [error, warning, info], example: warning }
        code: { type: string, example: long_title }
        message: { type: string, example: "El title es muy largo (72 caracteres)." }
        fix: { type: string, example: "Recórtalo a ~60 caracteres." }
    ExtractResult:
      type: object
      properties:
        url: { type: string, example: "https://ejemplo.com/" }
        analyzedAt: { type: string, format: date-time }
        title: { type: string, nullable: true, example: "Ejemplo — Inicio" }
        meta:
          type: object
          properties:
            description: { type: string, nullable: true }
            keywords: { type: string, nullable: true }
            robots: { type: string, nullable: true }
            viewport: { type: string, nullable: true }
            ogTitle: { type: string, nullable: true }
            ogDescription: { type: string, nullable: true }
            ogImage: { type: string, nullable: true }
            twitterCard: { type: string, nullable: true }
        canonical: { type: string, nullable: true }
        language: { type: string, nullable: true, example: "es" }
        headingCount: { type: object, example: { h1: 1, h2: 4, h3: 2 } }
        headings:
          type: array
          items:
            type: object
            properties:
              level: { type: string, example: "h2" }
              text: { type: string }
        links:
          type: object
          properties:
            total: { type: integer, example: 42 }
            internal: { type: integer, example: 35 }
            external: { type: integer, example: 7 }
            nofollow: { type: integer, example: 3 }
        images:
          type: object
          properties:
            total: { type: integer, example: 12 }
            withoutAlt: { type: integer, example: 4 }
        wordCount: { type: integer, example: 845 }
        seoScore: { type: integer, minimum: 0, maximum: 100, example: 78 }
        issues:
          type: array
          items: { $ref: "#/components/schemas/Issue" }
    Error:
      type: object
      required: [error, message]
      properties:
        error: { type: string, example: invalid_url }
        message: { type: string, example: "La URL no es válida." }
    LicenseResult:
      type: object
      properties:
        ok: { type: boolean }
        valid: { type: boolean }
        plan: { type: string, nullable: true, example: "pro" }
        expiresAt: { type: string, format: date-time, nullable: true }
        reason: { type: string, nullable: true, example: "license_not_found" }
        demo: { type: boolean }
paths:
  /api/extract:
    post:
      summary: Analizar una URL
      description: Descarga el HTML de una URL pública y devuelve su metadata y auditoría SEO.
      security:
        - apiKey: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url: { type: string, format: uri, example: "https://ejemplo.com" }
                include:
                  type: array
                  items: { type: string, enum: [sample] }
                  description: 'Incluye ["sample"] para recibir listas de muestra de enlaces e imágenes (máx. 50 c/u).'
      responses:
        "200":
          description: Análisis completado
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean, example: true }
                  data: { $ref: "#/components/schemas/ExtractResult" }
        "400": { description: Parámetros inválidos, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
        "401": { description: Falta la API key, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
        "403": { description: API key inválida, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
        "422": { description: La URL no es HTML o es demasiado grande, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
        "429": { description: Rate limit excedido, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
        "502": { description: No se pudo descargar la URL, content: { application/json: { schema: { $ref: "#/components/schemas/Error" } } } }
  /api/verify-license:
    post:
      summary: Validar licencia PRO
      description: Valida una licencia de la extensión (formato LIC-XXXX-XXXX) contra suscripciones activas de Stripe.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [license]
              properties:
                license: { type: string, example: "LIC-AB12-CD34" }
                device: { type: string, description: ID opcional de instalación }
      responses:
        "200":
          description: Resultado de la validación
          content:
            application/json:
              schema: { $ref: "#/components/schemas/LicenseResult" }
  /api/health:
    get:
      summary: Estado del servicio
      security: []
      responses:
        "200":
          description: Servicio operativo
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  service: { type: string }
                  version: { type: string }
                  time: { type: string, format: date-time }
                  stripeConfigured: { type: boolean }
