{
  "openapi": "3.1.0",
  "info": {
    "title": "Checkatron API",
    "version": "1.0.0",
    "description": "Trigger website quality scans, retrieve structured findings and compare two runs."
  },
  "servers": [
    { "url": "https://checkatron.com" }
  ],
  "paths": {
    "/api/v1/scans": {
      "post": {
        "operationId": "createScan",
        "summary": "Trigger a website scan",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": { "type": "string", "format": "uri", "maxLength": 2048 }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Scan accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ScanAccepted" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "429": { "$ref": "#/components/responses/Error" },
          "503": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/scans/{id}": {
      "get": {
        "operationId": "getScan",
        "summary": "Retrieve scan state and findings",
        "parameters": [
          { "$ref": "#/components/parameters/ScanId" }
        ],
        "responses": {
          "200": {
            "description": "Scan job",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Scan" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/api/v1/scans/{id}/diff": {
      "get": {
        "operationId": "compareScans",
        "summary": "Compare two completed scans of the same target",
        "parameters": [
          { "$ref": "#/components/parameters/ScanId" },
          {
            "name": "base",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "pattern": "^[a-f0-9]{32}$" }
          }
        ],
        "responses": {
          "200": {
            "description": "Finding-level delta",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ScanDiff" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "409": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "ScanId": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": { "type": "string", "pattern": "^[a-f0-9]{32}$" }
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" },
                "message": { "type": "string" }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "ScanAccepted": {
        "type": "object",
        "required": ["schemaVersion", "id", "status", "reportUrl", "apiUrl"],
        "properties": {
          "schemaVersion": { "const": "1.0" },
          "id": { "type": "string" },
          "status": { "const": "queued" },
          "reportUrl": { "type": "string" },
          "apiUrl": { "type": "string" }
        }
      },
      "Finding": {
        "type": "object",
        "required": ["severity", "rule", "title", "evidence", "pages"],
        "properties": {
          "severity": { "enum": ["high", "medium", "low"] },
          "rule": { "type": "string" },
          "title": { "type": "string" },
          "explanation": { "type": "string" },
          "evidence": { "type": "string" },
          "pages": { "type": "array", "items": { "type": "string" } }
        }
      },
      "Scan": {
        "type": "object",
        "required": ["schemaVersion", "id", "status", "target", "createdAt"],
        "properties": {
          "schemaVersion": { "const": "1.0" },
          "id": { "type": "string" },
          "status": { "enum": ["queued", "running", "complete", "failed"] },
          "target": { "type": "string", "format": "uri" },
          "createdAt": { "type": "string", "format": "date-time" },
          "completedAt": { "type": "string", "format": "date-time" },
          "error": { "type": "string" },
          "result": {
            "type": "object",
            "properties": {
              "findings": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } }
            }
          }
        }
      },
      "ScanDiff": {
        "type": "object",
        "required": ["schemaVersion", "baseScanId", "currentScanId", "summary", "added", "resolved", "unchanged"],
        "properties": {
          "schemaVersion": { "const": "1.0" },
          "baseScanId": { "type": "string" },
          "currentScanId": { "type": "string" },
          "summary": {
            "type": "object",
            "required": ["added", "resolved", "unchanged"],
            "properties": {
              "added": { "type": "integer" },
              "resolved": { "type": "integer" },
              "unchanged": { "type": "integer" }
            }
          },
          "added": { "type": "array", "items": { "type": "object" } },
          "resolved": { "type": "array", "items": { "type": "object" } },
          "unchanged": { "type": "array", "items": { "type": "object" } }
        }
      }
    }
  }
}
