{
  "openapi": "3.0.3",
  "info": {
    "title": "IsAgentReady API",
    "description": "JSON API for scanning websites for AI agent readiness. Returns scores, letter grades, and actionable recommendations across 5 categories.\n\n## Versioning and deprecation policy\n\nThe API is versioned in the URL path (`/api/v1`, `/api/v2`). Within a version, changes are additive: new fields and endpoints may appear, existing fields keep their type and meaning. Breaking changes ship as a new path version. When an endpoint or version is scheduled for removal it first returns `Deprecation: true` and `Sunset: <HTTP-date>` headers (RFC 9745 and RFC 8594) for at least 90 days, and the change is announced in the developer hub at https://isagentready.com/en/developers. Completed reports keep the methodology version they were scored with.\n\n## Rate limits\n\nEvery response carries `RateLimit-Policy`, `RateLimit`, `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` headers. Limited requests receive HTTP 429 with `Retry-After` and a problem-details body.\n\n## Errors\n\nErrors are RFC 9457 problem details (`application/json` with `type`, `title`, `status`, `detail`, `instance`). Unknown paths under `/api` return a 404 problem, never HTML.",
    "version": "1.0.0",
    "contact": {
      "name": "IsAgentReady",
      "url": "https://isagentready.com"
    }
  },
  "servers": [
    {
      "url": "https://isagentready.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/v1/scan/{domain}": {
      "get": {
        "operationId": "getScanResults",
        "summary": "Get latest scan results for a domain",
        "description": "Returns the most recent completed scan results for the given domain, including overall score, letter grade, per-category breakdowns, and individual checkpoint results with recommendations.",
        "tags": [
          "Scans"
        ],
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "The domain to get scan results for (e.g., example.com)",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Completed scan results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResult"
                }
              }
            }
          },
          "202": {
            "description": "Scan is in progress",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanPending"
                }
              }
            }
          },
          "404": {
            "description": "No scan found for this domain",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scan": {
      "post": {
        "operationId": "createScan",
        "summary": "Trigger a new scan",
        "description": "Start scanning a website for AI agent readiness. The scan runs asynchronously and typically takes 15-30 seconds. Poll GET /api/v1/scan/{domain} for results. If a recent scan exists (within 1 hour), returns the cached results instead.",
        "tags": [
          "Scans"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "The full URL to scan (must be http:// or https://)",
                    "example": "https://example.com"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Scan enqueued successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "description": "Scan ID"
                    },
                    "domain": {
                      "type": "string",
                      "description": "Normalized domain"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "running"
                      ]
                    },
                    "poll_url": {
                      "type": "string",
                      "description": "URL to poll for results"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "Recent scan exists (cooldown), returning cached results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Invalid URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded; retry after the number of seconds in the Retry-After header",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rankings": {
      "get": {
        "operationId": "getRankings",
        "summary": "Get AI readiness rankings",
        "description": "Returns a paginated, sorted list of website AI readiness scores. Supports filtering by grade range, category, and search.",
        "tags": [
          "Rankings"
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "grade_range",
            "in": "query",
            "required": false,
            "description": "Filter by grade range",
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "mid",
                "low"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Search by domain name",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Sort rankings by category score",
            "schema": {
              "type": "string",
              "enum": [
                "discovery",
                "search",
                "semantics",
                "protocols",
                "security"
              ]
            }
          },
          {
            "name": "industry",
            "in": "query",
            "required": false,
            "description": "Filter rankings by industry slug",
            "schema": {
              "type": "string",
              "enum": [
                "e-commerce",
                "news",
                "tech",
                "education",
                "government",
                "finance",
                "telecom",
                "travel",
                "logistics",
                "weather",
                "real-estate",
                "health",
                "energy",
                "food",
                "sports",
                "jobs",
                "culture",
                "entertainment",
                "insurance",
                "utilities"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Sort order",
            "schema": {
              "type": "string",
              "enum": [
                "score_desc",
                "score_asc",
                "domain",
                "newest"
              ],
              "default": "score_desc"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated rankings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entries": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RankingSummary"
                      }
                    },
                    "total": {
                      "type": "integer",
                      "description": "Total number of ranked websites"
                    },
                    "page": {
                      "type": "integer"
                    },
                    "per_page": {
                      "type": "integer"
                    },
                    "total_pages": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v2/rankings": {
      "get": {
        "operationId": "getCompactRankings",
        "summary": "Get compact AI readiness rankings",
        "description": "Returns paginated ranking summaries and one selected readiness profile without category or checkpoint bodies.",
        "tags": [
          "Rankings"
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            }
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 25,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "grade_range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "mid",
                "low"
              ]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Sort by an overall category score. This does not sort by profile score.",
            "schema": {
              "type": "string",
              "enum": [
                "discovery",
                "search",
                "semantics",
                "protocols",
                "security"
              ]
            }
          },
          {
            "name": "industry",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "e-commerce",
                "news",
                "tech",
                "education",
                "government",
                "finance",
                "telecom",
                "travel",
                "logistics",
                "weather",
                "real-estate",
                "health",
                "energy",
                "food",
                "sports",
                "jobs",
                "culture",
                "entertainment",
                "insurance",
                "utilities"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "score_desc",
                "score_asc",
                "domain",
                "newest"
              ],
              "default": "score_desc"
            }
          },
          {
            "name": "profile",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ai_search_visibility",
                "browser_agent_usability",
                "api_tool_readiness",
                "agentic_commerce"
              ],
              "default": "ai_search_visibility"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Compact paginated rankings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompactRankingsPage"
                }
              }
            }
          },
          "400": {
            "description": "Unknown profile identifier",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/monitoring/sites": {
      "post": {
        "operationId": "createMonitoringSite",
        "summary": "Create a site for monitoring",
        "description": "Create a pending monitor for a public website. A successful response immediately returns a one-time management bearer token and an HTTPS file challenge. Keep the token secret: this API does not email it.",
        "tags": ["Monitoring"],
        "requestBody": {
          "required": true,
          "content": {"application/json": {"schema": {"type": "object", "required": ["url"], "properties": {"url": {"type": "string", "format": "uri"}, "locale": {"type": "string", "enum": ["en", "nl"]}}}}}
        },
        "responses": {
          "201": {"description": "Pending monitoring site, file challenge, and management token returned immediately", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringClaimResponse"}}}},
          "400": {"description": "Missing claim URL", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
          "409": {"description": "Domain already monitored", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
          "422": {"description": "Invalid claim", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
          "429": {"description": "Rate limit exceeded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}
        }
      }
    },
    "/api/v1/monitoring/sites/{site_id}/verify": {
      "post": {
        "operationId": "verifyMonitoringSite",
        "summary": "Verify the site file challenge",
        "description": "Check the HTTPS file challenge returned when the monitoring site was created. It succeeds once the exact well-known file is reachable and matches the challenge. Authenticate with the management bearer token returned in that same creation response.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "responses": {"202": {"description": "Ownership verification queued", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringVerifyResponse"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "503": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/recovery": {
      "post": {
        "operationId": "recoverMonitoringSite",
        "summary": "Request a management recovery link",
        "description": "Request a recovery link for the management token of a verified site. The link is sent to the owner email on file and expires after a short window. Always answers 202 so the endpoint cannot be used to probe which sites exist.",
        "tags": ["Monitoring"],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "responses": {"202": {"description": "Recovery request accepted", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringRecoveryResponse"}}}}, "429": {"description": "Rate limit exceeded", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}": {
      "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
      "get": {
        "operationId": "getMonitoringSite",
        "summary": "Get monitoring configuration",
        "description": "Return the monitoring configuration of a verified site: cadence, pause state, active policy version, notification channels and the last completed run. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "responses": {"200": {"description": "Monitoring site", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringSite"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      },
      "patch": {
        "operationId": "updateMonitoringSite",
        "summary": "Pause, resume, or change cadence",
        "description": "Pause or resume the monitor, or change its cadence. Changes apply to the next scheduled run. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringSiteUpdateInput"}}}},
        "responses": {"200": {"description": "Updated site", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringSite"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      },
      "delete": {
        "operationId": "deleteMonitoringSite",
        "summary": "Delete the monitor and its history",
        "description": "Permanently delete the monitor together with its run history, policies, channels, private imports and pending accountless setup data for the website. Public scan reports of the domain are not affected. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "responses": {"204": {"description": "Deleted"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/policy": {
      "get": {
        "operationId": "getMonitoringPolicy",
        "summary": "Get the active immutable policy snapshot",
        "description": "Return the active readiness policy snapshot: its profile, baseline scan, required checkpoints, exceptions and methodology version. Policies are immutable; a new version replaces the active one.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "responses": {"200": {"description": "Active policy", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringPolicy"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/policies": {
      "post": {
        "operationId": "createMonitoringPolicy",
        "summary": "Create and activate a new policy version",
        "description": "Create a new immutable policy version and activate it. Previous versions remain readable in history so gate results stay reproducible. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringPolicyInput"}}}},
        "responses": {"200": {"description": "Existing idempotent policy version", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringPolicy"}}}}, "201": {"description": "New policy version", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringPolicy"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/history": {
      "get": {
        "operationId": "getMonitoringHistory",
        "summary": "List monitoring runs",
        "description": "List completed monitoring runs, newest first, with score, grade, methodology version and gate outcome. Supports cursor pagination. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100}}, {"name": "before", "in": "query", "schema": {"type": "string", "format": "uuid"}}],
        "responses": {"200": {"description": "Monitoring history", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringHistoryResponse"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/runs/{run_id}/diff": {
      "get": {
        "operationId": "getMonitoringDiff",
        "summary": "Compare two monitoring runs",
        "description": "Compare two monitoring runs of the same site and return checkpoints that changed status or score. Runs on different methodology versions are compared per checkpoint id with the version difference flagged.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "run_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}],
        "responses": {"200": {"description": "Run diff", "content": {"application/json": {"schema": {"type": "object"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/status": {
      "get": {
        "operationId": "getMonitoringStatus",
        "summary": "Get readiness gate status",
        "description": "Return the current readiness gate status: pass or fail against the active policy, the run it was evaluated on and the checkpoints that block a pass. Suitable for CI gates.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "responses": {"200": {"description": "Latest run passed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringStatus"}}}}, "202": {"description": "No terminal run yet", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringStatus"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "412": {"description": "Latest run failed policy", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringStatus"}}}}, "503": {"description": "Latest scan failed", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringStatus"}}}}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/channels": {
      "post": {
        "operationId": "createMonitoringChannel",
        "summary": "Create an email or webhook channel",
        "description": "Create an email or webhook notification channel. Webhook channels receive signed JSON deliveries; the signing secret is returned once on creation. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringChannelInput"}}}},
        "responses": {"201": {"description": "Channel and optional one-time webhook secret", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringChannelResponse"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/channels/{channel_id}/rotate-secret": {
      "post": {
        "operationId": "rotateMonitoringChannelSecret",
        "summary": "Rotate a webhook signing secret",
        "description": "Rotate the signing secret of a webhook channel. The new secret is returned once; deliveries signed with the old secret stop immediately.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"$ref": "#/components/parameters/MonitoringChannelId"}],
        "responses": {"200": {"description": "Rotated one-time webhook secret", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MonitoringChannelResponse"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/channels/{channel_id}": {
      "delete": {
        "operationId": "deleteMonitoringChannel",
        "summary": "Delete a notification channel",
        "description": "Delete a notification channel. Pending deliveries to the channel are dropped. Requires the management bearer token.",
        "tags": ["Monitoring"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"$ref": "#/components/parameters/MonitoringChannelId"}],
        "responses": {"204": {"description": "Deleted"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/outcome-imports/search-console": {
      "post": {
        "operationId": "importSearchConsoleOutcomes",
        "summary": "Import bounded Search Console daily evidence",
        "description": "Requires a verified, unexpired owner. The raw application/octet-stream body uses the IARSC1 envelope containing separate Dates.csv and Filters.csv bytes, each capped at 2 MiB. Authentication runs before the body is consumed. Query and page exports are not accepted. Provenance is owner_uploaded_search_console_csv and associations never establish causation.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "request_id", "in": "query", "required": true, "schema": {"type": "string", "format": "uuid"}}, {"name": "property", "in": "query", "required": true, "schema": {"type": "string"}}],
        "requestBody": {"required": true, "content": {"application/octet-stream": {"schema": {"type": "string", "format": "binary"}}}},
        "responses": {"200": {"description": "Completed import or idempotent original", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutcomeImport"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/outcome-imports/crawler-log": {
      "post": {
        "operationId": "importCrawlerLogOutcomes",
        "summary": "Import a bounded canonical crawler-log CSV",
        "description": "Requires a verified, unexpired owner. Authentication runs before the raw text/csv or application/octet-stream body is consumed. The body is capped at 25 MiB and 250000 rows. Raw IP addresses, full user agents, paths and referers are discarded. Verified counts mean matched provider-published range snapshot, not cryptographic attestation.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "request_id", "in": "query", "required": true, "schema": {"type": "string", "format": "uuid"}}],
        "requestBody": {"required": true, "content": {"text/csv": {"schema": {"type": "string", "format": "binary"}}, "application/octet-stream": {"schema": {"type": "string", "format": "binary"}}}},
        "responses": {"200": {"description": "Completed import or idempotent original", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutcomeImport"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}, "503": {"description": "No complete official crawler source snapshot available"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/outcome-imports/{batch_id}": {
      "delete": {
        "operationId": "deleteOutcomeImport",
        "summary": "Hard-delete one private import and its aggregates",
        "description": "Hard-delete one private outcome import batch (Search Console or crawler log rows) and the aggregates derived from it. Requires the management bearer token.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "batch_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}],
        "responses": {"204": {"description": "Private import deleted"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/discoverability-observations": {
      "post": {
        "operationId": "importDiscoverabilityObservations",
        "summary": "Import bounded provider-neutral discoverability observations",
        "description": "Requires a verified, unexpired owner. Validates every observation before one atomic import. Evidence is experimental, excluded from every score, and never supports a causal claim.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DiscoverabilityObservationImportInput"}}}},
        "responses": {"201": {"description": "Immutable batch created or idempotent original returned", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/DiscoverabilityObservationBatch"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "409": {"description": "Request identifier was reused for different content", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/discoverability-observations/{batch_id}": {
      "delete": {
        "operationId": "deleteDiscoverabilityObservationBatch",
        "summary": "Hard-delete one private discoverability batch",
        "description": "Hard-delete one private batch of external discoverability observations and the aggregates derived from it. Requires the management bearer token.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "batch_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}],
        "responses": {"204": {"description": "Private discoverability batch deleted"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/outcomes": {
      "get": {
        "operationId": "getOutcomeTimeline",
        "summary": "Get bounded private outcome and intervention evidence",
        "description": "Returns descriptive observations with causal_claim false. Search Console uses America/Los_Angeles source days and crawler logs use UTC.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "date_from", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "date_to", "in": "query", "schema": {"type": "string", "format": "date"}}, {"name": "batch_ids", "in": "query", "schema": {"type": "string"}}],
        "responses": {"200": {"description": "Private bounded timeline", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutcomeTimeline"}}}}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/interventions": {
      "post": {
        "operationId": "createOutcomeIntervention",
        "summary": "Create one immutable owner intervention",
        "description": "Record an immutable owner intervention (for example: published llms.txt on a given date) so later runs and imported outcomes can be read against it. Interventions never imply causation in reports.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/OutcomeInterventionInput"}}}},
        "responses": {"201": {"description": "Immutable intervention created"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}, "422": {"$ref": "#/components/responses/MonitoringInvalid"}}
      }
    },
    "/api/v1/monitoring/sites/{site_id}/interventions/{intervention_id}": {
      "delete": {
        "operationId": "deleteOutcomeIntervention",
        "summary": "Hard-delete one owner intervention",
        "description": "Hard-delete one owner intervention. Requires the management bearer token.",
        "tags": ["Outcomes"],
        "security": [{"bearerAuth": []}],
        "parameters": [{"$ref": "#/components/parameters/MonitoringSiteId"}, {"name": "intervention_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}],
        "responses": {"204": {"description": "Intervention deleted"}, "404": {"$ref": "#/components/responses/MonitoringNotFound"}}
      }
    },
    "/api/v2/benchmarks/state-of-agent-ready-web/{version}": {
      "get": {
        "operationId": "getStateOfAgentReadyWebBenchmark",
        "summary": "Get one immutable published benchmark snapshot",
        "description": "Aggregate research for a fixed sample of eligible, previously submitted public sites. It is not an estimate of all websites and never includes private outcome imports.",
        "tags": ["Benchmarks"],
        "parameters": [{"name": "version", "in": "path", "required": true, "schema": {"type": "string"}}],
        "responses": {"200": {"description": "Persisted immutable aggregate snapshot", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BenchmarkSnapshot"}}}}, "404": {"description": "Unknown or unpublished version"}}
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcpRequest",
        "summary": "MCP Streamable HTTP endpoint",
        "description": "Model Context Protocol server endpoint. Send JSON-RPC 2.0 requests to interact with the IsAgentReady scanner tools. Supports initialize, tools/list, and tools/call methods.",
        "tags": [
          "MCP"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "const": "2.0"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "initialize",
                      "tools/list",
                      "tools/call"
                    ],
                    "description": "The JSON-RPC method to call"
                  },
                  "id": {
                    "description": "Request ID (omit for notifications)",
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "integer"
                      }
                    ]
                  },
                  "params": {
                    "type": "object",
                    "description": "Method-specific parameters"
                  }
                },
                "required": [
                  "jsonrpc",
                  "method"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jsonrpc": {
                      "type": "string",
                      "const": "2.0"
                    },
                    "result": {
                      "type": "object"
                    },
                    "id": {}
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "iar_mon_ token"
      }
    },
    "parameters": {
      "MonitoringSiteId": {"name": "site_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}},
      "MonitoringChannelId": {"name": "channel_id", "in": "path", "required": true, "schema": {"type": "string", "format": "uuid"}}
    },
    "responses": {
      "MonitoringNotFound": {"description": "Site or resource not found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
      "MonitoringInvalid": {"description": "Invalid monitoring request", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}
    },
    "schemas": {
      "ScanResult": {
        "type": "object",
        "required": ["access_blockers"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domain": {
            "type": "string",
            "example": "example.com"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "canceled"
            ]
          },
          "overall_score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Overall AI readiness score"
          },
          "letter_grade": {
            "type": "string",
            "enum": [
              "F",
              "D",
              "C",
              "B",
              "A",
              "A+"
            ],
            "description": "Letter grade based on overall score"
          },
          "methodology_version": {
            "type": "string",
            "description": "Immutable scoring methodology version, or legacy for historical scans"
          },
          "schema_version": {
            "type": "string",
            "description": "Version of the canonical public report representation"
          },
          "report_url": {
            "type": "string",
            "description": "Localized URL for the latest report"
          },
          "snapshot_url": {
            "type": "string",
            "description": "Localized immutable URL for this exact scan"
          },
          "scanned_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "score_breakdown": {
            "type": "object",
            "description": "Canonical stable-core and adoption score breakdown"
          },
          "surfaces": {
            "type": "object",
            "description": "Detected agent-facing surfaces and their persisted classification"
          },
          "issues": {
            "type": "array",
            "description": "Prioritized failed and partial checkpoints",
            "items": {
              "type": "object",
              "required": ["maturity", "access_blocker"],
              "properties": {
                "id": {"type": "string"},
                "category": {"type": "string"},
                "name": {"type": "string"},
                "status": {"type": "string"},
                "priority": {"type": "string", "enum": ["high", "medium"]},
                "potential_gain": {"type": "integer"},
                "recommendation": {"type": "string", "nullable": true},
                "evidence": {"type": "string", "nullable": true},
                "references": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "required": ["title", "url"],
                    "properties": {
                      "title": {"type": "string", "maxLength": 240},
                      "url": {"type": "string", "maxLength": 2048}
                    }
                  }
                },
                "maturity": {
                  "type": "string",
                  "enum": ["essential", "recommended", "emerging"]
                },
                "access_blocker": {"type": "boolean"}
              }
            }
          },
          "access_blockers": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["kind", "provider", "title"],
              "properties": {
                "kind": {"type": "string"},
                "provider": {"type": "string"},
                "title": {"type": "string"}
              }
            }
          },
          "browser_journeys": {
            "type": "object",
            "description": "Qualitative browser evidence excluded from the numeric score",
            "properties": {
              "included_in_score": {"type": "boolean", "enum": [false]},
              "evidence": {"type": "array", "items": {"type": "object"}}
            }
          },
          "profiles": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ProfileResults"
              },
              {
                "type": "null"
              }
            ]
          },
          "scan_duration_ms": {
            "type": "integer",
            "description": "Scan duration in milliseconds"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time"
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Category"
            }
          },
          "browser_tasks": {
            "type": "array",
            "description": "Optional experimental browser evidence. It is not included in readiness scores.",
            "items": {
              "$ref": "#/components/schemas/BrowserTaskEvidence"
            }
          }
        }
      },
      "RankingSummary": {
        "type": "object",
        "description": "Compact scan summary returned by the V1 rankings endpoint.",
        "required": [
          "id",
          "domain",
          "status",
          "overall_score",
          "letter_grade",
          "methodology_version",
          "profiles",
          "scan_duration_ms",
          "completed_at",
          "categories"
        ],
        "properties": {
          "id": {"type": "string", "format": "uuid"},
          "domain": {"type": "string", "example": "example.com"},
          "status": {
            "type": "string",
            "enum": ["pending", "running", "completed", "failed", "canceled"]
          },
          "overall_score": {"type": "integer", "minimum": 0, "maximum": 100},
          "letter_grade": {"type": "string", "enum": ["F", "D", "C", "B", "A", "A+"]},
          "methodology_version": {"type": "string"},
          "profiles": {
            "$ref": "#/components/schemas/ProfileResults"
          },
          "scan_duration_ms": {"type": "integer", "minimum": 0},
          "completed_at": {"type": "string", "format": "date-time"},
          "categories": {
            "type": "array",
            "items": {"$ref": "#/components/schemas/Category"}
          },
          "browser_tasks": {
            "type": "array",
            "deprecated": true,
            "description": "Deprecated compatibility property. Browser evidence is available from the scan detail endpoint and is omitted from ranking responses.",
            "items": {"$ref": "#/components/schemas/BrowserTaskEvidence"}
          }
        }
      },
      "BrowserTaskEvidence": {
        "type": "object",
        "properties": {
          "task_key": {"type": "string"},
          "objective": {"type": "string"},
          "status": {"type": "string", "enum": ["pending", "running", "completed", "failed", "skipped"]},
          "outcome": {"type": "string", "nullable": true, "enum": ["success", "partial", "failure", "not_applicable"]},
          "protocol_path": {"type": "string", "nullable": true},
          "evidence": {"type": "object"},
          "failure_code": {"type": "string", "nullable": true},
          "probe_version": {"type": "string"},
          "experimental": {"type": "boolean", "enum": [true]},
          "included_in_score": {"type": "boolean", "enum": [false]}
        },
        "required": ["task_key", "objective", "status", "probe_version", "experimental", "included_in_score"]
      },
      "ScanPending": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "domain": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running"
            ]
          },
          "methodology_version": {
            "type": "string"
          },
          "profiles": {
            "type": "null",
            "description": "Profile snapshot is populated only when the scan completes"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Category": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Canonical category identifier"
          },
          "category": {
            "type": "string",
            "enum": [
              "discovery",
              "structured_data",
              "semantics",
              "agent_protocols",
              "security"
            ],
            "description": "Category identifier"
          },
          "label": {
            "type": "string",
            "description": "Human-readable category name"
          },
          "score": {
            "type": "integer",
            "description": "Points scored"
          },
          "max_score": {
            "type": "integer",
            "description": "Maximum possible points"
          },
          "percentage": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "Canonical percentage score for this category"
          },
          "weight": {
            "type": "integer",
            "description": "Category weight as percentage (e.g., 30 for 30%)"
          },
          "checkpoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Checkpoint"
            }
          }
        }
      },
      "Checkpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Checkpoint ID (e.g., '1.1', '4.3')"
          },
          "name": {
            "type": "string",
            "description": "Checkpoint name"
          },
          "status": {
            "type": "string",
            "enum": [
              "pass",
              "partial",
              "fail",
              "skip"
            ]
          },
          "score": {
            "type": "integer",
            "description": "Points scored"
          },
          "max_score": {
            "type": "integer",
            "description": "Maximum possible points"
          },
          "evidence_tier": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "standard",
                  "supported",
                  "emerging",
                  "experimental"
                ]
              },
              {
                "type": "null"
              }
            ],
            "description": "Evidence maturity for this methodology version"
          },
          "profile_applicability": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "ai_search_visibility",
                "browser_agent_usability",
                "api_tool_readiness",
                "agentic_commerce"
              ]
            }
          },
          "details": {
            "type": "string",
            "description": "What was found or not found"
          },
          "recommendation": {
            "type": "string",
            "description": "Actionable recommendation for improvement"
          },
          "why": {
            "type": "string",
            "description": "Why this checkpoint matters"
          },
          "code_example": {
            "type": "string",
            "description": "Example code to implement the recommendation"
          },
          "references": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["title", "url"],
              "properties": {
                "title": {"type": "string", "maxLength": 240},
                "url": {"type": "string", "maxLength": 2048}
              }
            },
            "description": "Public references supporting the checkpoint"
          },
          "score_role": {
            "type": "string",
            "nullable": true,
            "description": "Role of this checkpoint in the stored methodology"
          },
          "surface_applicability": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Detected surfaces to which this checkpoint applies"
          }
        }
      },
      "ProfileResults": {
        "type": "object",
        "properties": {
          "ai_search_visibility": {
            "$ref": "#/components/schemas/ProfileResult"
          },
          "browser_agent_usability": {
            "$ref": "#/components/schemas/ProfileResult"
          },
          "api_tool_readiness": {
            "$ref": "#/components/schemas/ProfileResult"
          },
          "agentic_commerce": {
            "$ref": "#/components/schemas/ProfileResult"
          }
        }
      },
      "ProfileResult": {
        "type": "object",
        "properties": {
          "score": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "applicable_score": {
            "type": "integer"
          },
          "applicable_max_score": {
            "type": "integer"
          },
          "applicable": {
            "type": "boolean"
          },
          "methodology_version": {
            "type": "string"
          }
        }
      },
      "CompactRankingsPage": {
        "type": "object",
        "required": [
          "entries",
          "total",
          "page",
          "per_page",
          "total_pages"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompactRankingEntry"
            }
          },
          "total": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        }
      },
      "CompactRankingEntry": {
        "type": "object",
        "required": [
          "domain",
          "overall_score",
          "letter_grade",
          "profile",
          "methodology_version",
          "completed_at"
        ],
        "properties": {
          "domain": {
            "type": "string"
          },
          "overall_score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "letter_grade": {
            "type": "string",
            "enum": [
              "F",
              "D",
              "C",
              "B",
              "A",
              "A+"
            ]
          },
          "profile": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/CompactProfile"
              }
            ]
          },
          "methodology_version": {
            "type": "string"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CompactProfile": {
        "type": "object",
        "required": [
          "id",
          "score",
          "applicable"
        ],
        "properties": {
          "id": {
            "type": "string",
            "enum": [
              "ai_search_visibility",
              "browser_agent_usability",
              "api_tool_readiness",
              "agentic_commerce"
            ]
          },
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "nullable": true
          },
          "applicable": {
            "type": "boolean"
          }
        }
      },
      "MonitoringSite": {
        "type": "object",
        "required": ["id", "domain", "status", "schedule", "next_run_at", "current_policy_version", "locale", "ownership_expires_at", "channels"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "domain": {"type": "string"}, "status": {"type": "string", "enum": ["pending", "verified", "paused", "ownership_lost"]}, "schedule": {"type": "string", "enum": ["daily", "weekly"], "nullable": true}, "next_run_at": {"type": "string", "format": "date-time", "nullable": true}, "current_policy_version": {"type": "integer", "minimum": 0}, "locale": {"type": "string", "enum": ["en", "nl"]}, "ownership_expires_at": {"type": "string", "format": "date-time", "nullable": true}, "channels": {"type": "array", "items": {"$ref": "#/components/schemas/MonitoringChannel"}}}
      },
      "MonitoringClaimResponse": {
        "type": "object",
        "required": ["site", "management_token", "proof_url", "challenge"],
        "properties": {"site": {"$ref": "#/components/schemas/MonitoringSite"}, "management_token": {"type": "string", "writeOnly": true}, "proof_url": {"type": "string", "format": "uri"}, "challenge": {"type": "string"}}
      },
      "MonitoringVerifyResponse": {
        "type": "object",
        "required": ["status"],
        "properties": {"status": {"type": "string", "enum": ["verification_queued"]}}
      },
      "MonitoringRecoveryResponse": {
        "type": "object",
        "required": ["status"],
        "properties": {"status": {"type": "string", "enum": ["recovery_requested"]}}
      },
      "MonitoringSiteUpdateInput": {
        "type": "object",
        "properties": {"status": {"type": "string", "enum": ["verified", "paused"]}, "schedule": {"type": "string", "enum": ["daily", "weekly"]}, "locale": {"type": "string", "enum": ["en", "nl"]}}
      },
      "MonitoringPolicyInput": {
        "type": "object",
        "required": ["request_id", "schema_version", "profile", "baseline_scan_id", "required_checks", "exceptions"],
        "properties": {"request_id": {"type": "string", "format": "uuid"}, "schema_version": {"type": "string", "enum": ["1"]}, "profile": {"type": "string", "enum": ["ai_search_visibility", "browser_agent_usability", "api_tool_readiness", "agentic_commerce"]}, "baseline_scan_id": {"type": "string", "format": "uuid"}, "required_checks": {"type": "array", "items": {"type": "object", "required": ["id", "minimum_status"], "properties": {"id": {"type": "string"}, "minimum_status": {"type": "string", "enum": ["fail", "partial", "pass"]}}}, "exceptions": {"type": "array", "items": {"type": "object", "required": ["checkpoint_id", "reason", "expires_at"], "properties": {"checkpoint_id": {"type": "string"}, "reason": {"type": "string"}, "expires_at": {"type": "string", "format": "date-time"}}}}}}
      },
      "MonitoringPolicy": {
        "type": "object",
        "required": ["id", "version", "schema_version", "methodology_version", "profile", "baseline_scan_id", "required_checks", "exceptions", "created_at"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "version": {"type": "integer", "minimum": 1}, "schema_version": {"type": "string"}, "methodology_version": {"type": "string"}, "profile": {"type": "string"}, "baseline_scan_id": {"type": "string", "format": "uuid"}, "required_checks": {"type": "array", "items": {"type": "object"}}, "exceptions": {"type": "array", "items": {"type": "object"}}, "created_at": {"type": "string", "format": "date-time"}}
      },
      "MonitoringRun": {
        "type": "object",
        "required": ["id", "scan_id", "policy_id", "baseline_scan_id", "scheduled_for", "status", "conclusion", "severity", "methodology_changed", "result", "evaluated_at"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "scan_id": {"type": "string", "format": "uuid"}, "policy_id": {"type": "string", "format": "uuid"}, "baseline_scan_id": {"type": "string", "format": "uuid"}, "scheduled_for": {"type": "string", "format": "date-time"}, "status": {"type": "string", "enum": ["awaiting_scan", "evaluated", "scan_failed"]}, "conclusion": {"type": "string", "enum": ["success", "failure", "neutral", "error"], "nullable": true}, "severity": {"type": "string", "enum": ["none", "info", "warning", "critical"], "nullable": true}, "methodology_changed": {"type": "boolean"}, "result": {"type": "object", "nullable": true}, "evaluated_at": {"type": "string", "format": "date-time", "nullable": true}}
      },
      "MonitoringHistoryResponse": {
        "type": "object",
        "required": ["runs"],
        "properties": {"runs": {"type": "array", "items": {"$ref": "#/components/schemas/MonitoringRun"}}}
      },
      "MonitoringStatus": {
        "type": "object",
        "required": ["run_id", "generated_at", "latest_run_at", "next_run_at"],
        "properties": {"run_id": {"type": "string", "format": "uuid"}, "generated_at": {"type": "string", "format": "date-time"}, "latest_run_at": {"type": "string", "format": "date-time"}, "next_run_at": {"type": "string", "format": "date-time", "nullable": true}, "schema_version": {"type": "string"}, "site_id": {"type": "string", "format": "uuid"}, "policy": {"type": "object"}, "baseline": {"type": "object"}, "current": {"type": "object"}, "evaluated_at": {"type": "string", "format": "date-time"}, "comparison": {"type": "string", "enum": ["comparable", "methodology_changed", "scan_failed"]}, "conclusion": {"type": "string", "enum": ["success", "failure", "neutral", "error"]}, "severity": {"type": "string", "enum": ["none", "info", "warning", "critical"]}, "methodology_changed": {"type": "boolean"}, "profile_delta": {"type": "integer", "nullable": true}, "changes": {"type": "array", "items": {"type": "object"}}, "violations": {"type": "array", "items": {"type": "object"}}}
      },
      "MonitoringChannelInput": {
        "type": "object",
        "required": ["request_id", "kind", "target"],
        "properties": {"request_id": {"type": "string", "format": "uuid"}, "kind": {"type": "string", "enum": ["email", "webhook"]}, "target": {"type": "string"}}
      },
      "MonitoringChannel": {
        "type": "object",
        "required": ["id", "kind", "status", "target", "verified_at"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "kind": {"type": "string", "enum": ["email", "webhook"]}, "status": {"type": "string", "enum": ["pending", "verified", "disabled"]}, "target": {"type": "string", "description": "Masked destination"}, "verified_at": {"type": "string", "format": "date-time", "nullable": true}}
      },
      "MonitoringChannelResponse": {
        "type": "object",
        "required": ["channel"],
        "properties": {"channel": {"$ref": "#/components/schemas/MonitoringChannel"}, "webhook_secret": {"type": "string", "writeOnly": true}}
      },
      "OutcomeImport": {
        "type": "object",
        "required": ["id", "source_type", "status", "schema_version", "source_date_from", "source_date_to", "source_timezone", "source_scope", "accepted_rows", "rejected_rows", "unverified_rows", "provenance", "retention_expires_at"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "source_type": {"type": "string", "enum": ["search_console", "crawler_log"]}, "status": {"type": "string", "enum": ["completed"]}, "schema_version": {"type": "string", "enum": ["1"]}, "source_date_from": {"type": "string", "format": "date"}, "source_date_to": {"type": "string", "format": "date"}, "source_timezone": {"type": "string", "enum": ["America/Los_Angeles", "UTC"]}, "source_scope": {"type": "object"}, "accepted_rows": {"type": "integer", "minimum": 0}, "rejected_rows": {"type": "integer", "minimum": 0}, "unverified_rows": {"type": "integer", "minimum": 0}, "provenance": {"type": "string", "enum": ["owner_uploaded_search_console_csv", "owner_uploaded_canonical_crawler_log"]}, "retention_expires_at": {"type": "string", "format": "date-time"}}
      },
      "DiscoverabilityObservationImportInput": {
        "type": "object",
        "additionalProperties": false,
        "required": ["request_id", "schema_version", "provider", "model", "locale", "provenance", "observations"],
        "properties": {"request_id": {"type": "string", "format": "uuid"}, "schema_version": {"type": "string", "enum": ["1"]}, "provider": {"type": "string", "minLength": 1, "maxLength": 80, "x-maxBytes": 80, "description": "Provider identifier, capped at 80 UTF-8 bytes."}, "model": {"type": "string", "minLength": 1, "maxLength": 120, "x-maxBytes": 120, "description": "Model or engine identifier, capped at 120 UTF-8 bytes."}, "locale": {"type": "string", "minLength": 2, "maxLength": 35, "x-maxBytes": 35, "description": "Normalized locale, capped at 35 UTF-8 bytes."}, "provenance": {"type": "object", "maxProperties": 20, "x-maxBytes": 4000, "description": "Credential-free provenance metadata, capped at 4000 canonical JSON bytes. Secret key names are rejected after separator and case normalization."}, "observations": {"type": "array", "minItems": 1, "maxItems": 20, "uniqueItems": true, "items": {"$ref": "#/components/schemas/DiscoverabilityObservationInput"}}}
      },
      "DiscoverabilityObservationInput": {
        "type": "object",
        "additionalProperties": false,
        "required": ["probe_key", "status", "evidence_source", "observed_at"],
        "oneOf": [{"description": "A found observation. Position is optional. Brand and developer probes require a credential-free same-site citation URL, with subdomains allowed only by the immutable probe definition.", "properties": {"status": {"type": "string", "enum": ["found"]}}, "oneOf": [{"properties": {"probe_key": {"type": "string", "enum": ["brand_discovery", "developer_discovery"]}, "citation_url": {"type": "string", "format": "uri", "nullable": false}}, "required": ["citation_url"]}, {"properties": {"probe_key": {"type": "string", "enum": ["recommendation_presence"]}}}]}, {"description": "A non-found, ambiguous, or error observation. Position must be null or absent.", "properties": {"status": {"type": "string", "enum": ["not_found", "ambiguous", "error"]}, "position": {"type": "integer", "nullable": true, "enum": [null]}}}],
        "properties": {"probe_key": {"type": "string", "enum": ["brand_discovery", "developer_discovery", "recommendation_presence"], "maxLength": 80, "x-maxBytes": 80}, "status": {"type": "string", "enum": ["found", "not_found", "ambiguous", "error"]}, "position": {"type": "integer", "minimum": 1, "maximum": 10000, "nullable": true, "description": "Allowed only when status is found."}, "citation_url": {"type": "string", "format": "uri", "maxLength": 2048, "x-maxBytes": 2048, "nullable": true, "description": "Credential-free HTTP(S) URL, capped at 2048 UTF-8 bytes. Required when brand_discovery or developer_discovery is found. Any supplied citation for brand_discovery and developer_discovery, including non-found observations, is same-site validated. Subdomains are accepted only when the immutable probe definition allows them. Query and fragment parameters may not contain credential names or values."}, "answer_summary": {"type": "string", "maxLength": 2000, "x-maxBytes": 2000, "nullable": true}, "evidence_source": {"type": "string", "enum": ["provider_response", "provider_citation", "manual_review"]}, "evidence": {"type": "string", "maxLength": 4000, "x-maxBytes": 4000, "nullable": true}, "observed_at": {"type": "string", "format": "date-time", "maxLength": 64, "x-maxBytes": 64}}
      },
      "DiscoverabilityObservationBatch": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "request_id", "schema_version", "probe_set_version", "probe_set_hash", "provider", "model", "locale", "provenance", "observation_count", "experimental", "included_in_score", "causal_claim", "inserted_at", "observations"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "request_id": {"type": "string", "format": "uuid"}, "schema_version": {"type": "string", "enum": ["1"]}, "probe_set_version": {"type": "string"}, "probe_set_hash": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "provider": {"type": "string"}, "model": {"type": "string"}, "locale": {"type": "string"}, "provenance": {"type": "object"}, "observation_count": {"type": "integer", "minimum": 1, "maximum": 20}, "experimental": {"type": "boolean", "enum": [true]}, "included_in_score": {"type": "boolean", "enum": [false]}, "causal_claim": {"type": "boolean", "enum": [false]}, "inserted_at": {"type": "string", "format": "date-time"}, "observations": {"type": "array", "items": {"$ref": "#/components/schemas/DiscoverabilityObservation"}}}
      },
      "DiscoverabilityObservation": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "batch_id", "probe_set_version", "probe_set_hash", "provider", "model", "locale", "probe_key", "prompt_sha256", "status", "position", "citation_url", "answer_summary", "evidence_source", "evidence", "observed_at", "provenance", "experimental", "included_in_score", "causal_claim", "label"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "batch_id": {"type": "string", "format": "uuid"}, "probe_set_version": {"type": "string"}, "probe_set_hash": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "provider": {"type": "string"}, "model": {"type": "string"}, "locale": {"type": "string"}, "probe_key": {"type": "string"}, "prompt_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "status": {"type": "string", "enum": ["found", "not_found", "ambiguous", "error"]}, "position": {"type": "integer", "minimum": 1, "maximum": 10000, "nullable": true}, "citation_url": {"type": "string", "format": "uri", "nullable": true}, "answer_summary": {"type": "string", "nullable": true}, "evidence_source": {"type": "string", "enum": ["provider_response", "provider_citation", "manual_review"]}, "evidence": {"type": "string", "nullable": true}, "observed_at": {"type": "string", "format": "date-time"}, "provenance": {"type": "object"}, "experimental": {"type": "boolean", "enum": [true]}, "included_in_score": {"type": "boolean", "enum": [false]}, "causal_claim": {"type": "boolean", "enum": [false]}, "label": {"type": "string", "enum": ["observation"]}}
      },
      "OutcomeTimeline": {
        "type": "object",
        "required": ["date_from", "date_to", "selected_batches", "available_batches", "overlapping_batches", "daily_metrics", "interventions", "associations", "discoverability_associations", "discoverability_observations", "discoverability_observations_meta", "scans", "monitoring_runs", "interpretation", "causal_claim", "caveats"],
        "properties": {"date_from": {"type": "string", "format": "date"}, "date_to": {"type": "string", "format": "date"}, "selected_batches": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeBatchSummary"}}, "available_batches": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeBatchSummary"}}, "overlapping_batches": {"type": "object", "additionalProperties": {"type": "boolean"}}, "daily_metrics": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeDailyMetric"}}, "interventions": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeIntervention"}}, "associations": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeAssociation"}}, "discoverability_associations": {"type": "array", "items": {"$ref": "#/components/schemas/DiscoverabilityAssociation"}}, "discoverability_observations": {"type": "array", "maxItems": 100, "items": {"$ref": "#/components/schemas/DiscoverabilityObservation"}}, "discoverability_observations_meta": {"$ref": "#/components/schemas/DiscoverabilityObservationTimelineMeta"}, "scans": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeScanEvidence"}}, "monitoring_runs": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeMonitoringObservation"}}, "interpretation": {"type": "string", "enum": ["observed_association_only"]}, "causal_claim": {"type": "boolean", "enum": [false]}, "caveats": {"type": "array", "items": {"type": "string"}}}
      },
      "DiscoverabilityObservationTimelineMeta": {
        "type": "object",
        "additionalProperties": false,
        "required": ["limit", "returned", "truncated", "order"],
        "properties": {"limit": {"type": "integer", "enum": [100]}, "returned": {"type": "integer", "minimum": 0, "maximum": 100}, "truncated": {"type": "boolean"}, "order": {"type": "string", "enum": ["chronological"]}}
      },
      "OutcomeBatchSummary": {
        "type": "object",
        "required": ["id", "source_type", "date_from", "date_to", "source_timezone", "source_scope", "provenance", "retention_expires_at"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "source_type": {"type": "string", "enum": ["search_console", "crawler_log"]}, "date_from": {"type": "string", "format": "date"}, "date_to": {"type": "string", "format": "date"}, "source_timezone": {"type": "string", "enum": ["America/Los_Angeles", "UTC"]}, "source_scope": {"type": "object"}, "provenance": {"type": "string", "enum": ["owner_uploaded_search_console_csv", "owner_uploaded_canonical_crawler_log"]}, "retention_expires_at": {"type": "string", "format": "date-time"}}
      },
      "CrawlerSnapshotProvenance": {
        "type": "object",
        "required": ["id", "source_url", "provider_creation_time", "fetched_at", "content_sha256", "verification_basis"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "source_url": {"type": "string", "format": "uri"}, "provider_creation_time": {"type": "string", "format": "date-time"}, "fetched_at": {"type": "string", "format": "date-time"}, "content_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "verification_basis": {"type": "string", "enum": ["matched_provider_published_range_snapshot"]}}
      },
      "OutcomeDailyMetric": {
        "type": "object",
        "required": ["date", "metric_key", "evidence_kind", "value"],
        "properties": {"date": {"type": "string", "format": "date"}, "metric_key": {"type": "string"}, "provider": {"type": "string", "nullable": true}, "product": {"type": "string", "nullable": true}, "classifier_version": {"type": "string", "nullable": true}, "evidence_kind": {"type": "string", "enum": ["owner_uploaded", "verified_official_range", "claimed_historical", "unclassified", "classified_referral", "self_declared_utm"]}, "status_class": {"type": "integer", "minimum": 1, "maximum": 5, "nullable": true}, "crawler_source_snapshot": {"allOf": [{"$ref": "#/components/schemas/CrawlerSnapshotProvenance"}], "nullable": true}, "value": {"oneOf": [{"type": "integer"}, {"type": "string"}]}}
      },
      "OutcomeIntervention": {
        "type": "object",
        "required": ["id", "occurred_at", "kind", "title", "label"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "occurred_at": {"type": "string", "format": "date-time"}, "kind": {"type": "string", "enum": ["readiness_change", "content_change", "infrastructure_change", "measurement_change", "other"]}, "title": {"type": "string", "maxLength": 120}, "related_scan_id": {"type": "string", "format": "uuid", "nullable": true}, "label": {"type": "string", "enum": ["intervention"]}}
      },
      "OutcomeAssociation": {
        "type": "object",
        "required": ["intervention_id", "source", "status", "result"],
        "properties": {"intervention_id": {"type": "string", "format": "uuid"}, "source": {"type": "string", "enum": ["search_console", "crawler_log"]}, "status": {"type": "string", "enum": ["available", "insufficient_coverage", "source_version_mismatch", "methodology_version_mismatch"]}, "result": {"allOf": [{"$ref": "#/components/schemas/OutcomeAssociationResult"}], "nullable": true}}
      },
      "DiscoverabilityAssociation": {
        "type": "object",
        "additionalProperties": false,
        "required": ["intervention_id", "source", "probe_key", "identity", "status", "experimental", "included_in_score", "causal_claim", "result"],
        "properties": {"intervention_id": {"type": "string", "format": "uuid"}, "source": {"type": "string", "enum": ["discoverability"]}, "probe_key": {"type": "string"}, "identity": {"$ref": "#/components/schemas/DiscoverabilityObservationIdentity"}, "status": {"type": "string", "enum": ["available", "insufficient_coverage", "version_incompatible"]}, "experimental": {"type": "boolean", "enum": [true]}, "included_in_score": {"type": "boolean", "enum": [false]}, "causal_claim": {"type": "boolean", "enum": [false]}, "result": {"$ref": "#/components/schemas/DiscoverabilityAssociationResult"}}
      },
      "DiscoverabilityAssociationResult": {
        "type": "object",
        "additionalProperties": false,
        "required": ["analysis_version", "interpretation", "causal_claim", "before", "after", "incompatible_dimensions", "limitations"],
        "properties": {"analysis_version": {"type": "string", "enum": ["1"]}, "interpretation": {"type": "string", "enum": ["observed_association_only"]}, "causal_claim": {"type": "boolean", "enum": [false]}, "before": {"allOf": [{"$ref": "#/components/schemas/DiscoverabilityAssociationPoint"}], "nullable": true}, "after": {"allOf": [{"$ref": "#/components/schemas/DiscoverabilityAssociationPoint"}], "nullable": true}, "incompatible_dimensions": {"type": "array", "items": {"type": "string", "enum": ["probe_set_version", "probe_set_hash", "provider", "model", "locale", "probe_key", "prompt_sha256"]}}, "limitations": {"type": "array", "items": {"type": "string"}}}
      },
      "DiscoverabilityObservationIdentity": {
        "type": "object",
        "additionalProperties": false,
        "required": ["probe_set_version", "probe_set_hash", "provider", "model", "locale", "probe_key", "prompt_sha256"],
        "properties": {"probe_set_version": {"type": "string"}, "probe_set_hash": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "provider": {"type": "string"}, "model": {"type": "string"}, "locale": {"type": "string"}, "probe_key": {"type": "string"}, "prompt_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}}
      },
      "DiscoverabilityAssociationPoint": {
        "type": "object",
        "additionalProperties": false,
        "required": ["observation_id", "batch_id", "observed_at", "probe_set_version", "probe_set_hash", "provider", "model", "locale", "probe_key", "prompt_sha256", "status", "position", "citation_url"],
        "properties": {"observation_id": {"type": "string", "format": "uuid"}, "batch_id": {"type": "string", "format": "uuid"}, "observed_at": {"type": "string", "format": "date-time"}, "probe_set_version": {"type": "string"}, "probe_set_hash": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "provider": {"type": "string"}, "model": {"type": "string"}, "locale": {"type": "string"}, "probe_key": {"type": "string"}, "prompt_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, "status": {"type": "string", "enum": ["found", "not_found", "ambiguous", "error"]}, "position": {"type": "integer", "nullable": true}, "citation_url": {"type": "string", "format": "uri", "nullable": true}}
      },
      "OutcomeAssociationResult": {
        "type": "object",
        "required": ["analysis_version", "interpretation", "causal_claim", "window_days", "coverage", "methodology_version", "source_versions", "source_batch_ids", "metrics", "readiness", "browser_evidence", "limitations"],
        "properties": {"analysis_version": {"type": "string", "enum": ["1"]}, "interpretation": {"type": "string", "enum": ["observed_association_only"]}, "causal_claim": {"type": "boolean", "enum": [false]}, "window_days": {"type": "integer", "enum": [28]}, "coverage": {"type": "object", "additionalProperties": {"type": "object", "required": ["before", "after"], "properties": {"before": {"type": "integer"}, "after": {"type": "integer"}}}}, "methodology_version": {"type": "string", "nullable": true}, "source_versions": {"type": "object", "additionalProperties": {"oneOf": [{"type": "string"}, {"type": "object", "properties": {"registry_version": {"type": "string", "nullable": true}, "classifier_version": {"type": "string", "nullable": true}}}]}}, "source_batch_ids": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string", "format": "uuid"}}}, "metrics": {"type": "array", "items": {"type": "object"}}, "readiness": {"type": "object", "nullable": true, "description": "Exact before and after scan IDs, one methodology version, profile changes and checkpoint changes."}, "browser_evidence": {"type": "object", "required": ["status", "probe_versions", "evidence"], "properties": {"status": {"type": "string", "enum": ["compatible", "versioned_adjacent_only"]}, "probe_versions": {"type": "array", "items": {"type": "string"}}, "evidence": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeBrowserEvidence"}}}}, "limitations": {"type": "array", "items": {"type": "string"}}}
      },
      "OutcomeBrowserEvidence": {
        "type": "object",
        "required": ["outcome", "protocol_path", "probe_version", "experimental", "included_in_score"],
        "properties": {"outcome": {"type": "string"}, "protocol_path": {"type": "string"}, "probe_version": {"type": "string"}, "experimental": {"type": "boolean", "enum": [true]}, "included_in_score": {"type": "boolean", "enum": [false]}}
      },
      "OutcomeScanEvidence": {
        "type": "object",
        "required": ["id", "completed_at", "methodology_version", "profile_results", "label", "browser_tasks"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "completed_at": {"type": "string", "format": "date-time"}, "methodology_version": {"type": "string"}, "profile_results": {"type": "object"}, "overall_score": {"type": "integer", "nullable": true}, "letter_grade": {"type": "string", "nullable": true}, "label": {"type": "string", "enum": ["observation"]}, "browser_tasks": {"type": "array", "items": {"$ref": "#/components/schemas/OutcomeBrowserEvidence"}}}
      },
      "OutcomeMonitoringObservation": {
        "type": "object",
        "required": ["id", "scheduled_for", "status", "methodology_changed", "policy_id", "label"],
        "properties": {"id": {"type": "string", "format": "uuid"}, "scheduled_for": {"type": "string", "format": "date-time"}, "status": {"type": "string"}, "conclusion": {"type": "string", "nullable": true}, "methodology_changed": {"type": "boolean"}, "policy_id": {"type": "string", "format": "uuid"}, "label": {"type": "string", "enum": ["observation"]}}
      },
      "OutcomeInterventionInput": {
        "type": "object",
        "required": ["request_id", "occurred_at", "kind", "title"],
        "properties": {"request_id": {"type": "string", "format": "uuid"}, "occurred_at": {"type": "string", "format": "date-time"}, "kind": {"type": "string", "enum": ["readiness_change", "content_change", "infrastructure_change", "measurement_change", "other"]}, "title": {"type": "string", "maxLength": 120}, "related_scan_id": {"type": "string", "format": "uuid", "nullable": true}}
      },
      "BenchmarkSnapshot": {
        "type": "object",
        "description": "Immutable aggregate snapshot with sampling limitations, denominators, attrition, methodology and analysis versions. Browser evidence is experimental and non-scored.",
        "required": ["schema_version", "cohort_version", "report_version", "methodology_version", "profile", "analysis_version", "denominators", "attrition", "limitations"],
        "additionalProperties": true
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Scans",
      "description": "Trigger scans and retrieve results"
    },
    {
      "name": "Rankings",
      "description": "Browse AI readiness rankings"
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol server endpoint"
    },
    {
      "name": "Monitoring",
      "description": "Manage verified readiness monitoring and regression notifications"
    },
    {
      "name": "Outcomes",
      "description": "Manage private owner-uploaded aggregate outcome evidence without causal claims"
    },
    {
      "name": "Benchmarks",
      "description": "Read immutable aggregate research snapshots for a fixed submitted-site cohort"
    }
  ]
}
