{
  "openapi": "3.0.3",
  "info": {
    "title": "Dokven API",
    "version": "1.0.0",
    "description": "Programmatic access to Dokven's URL-first QA modules. All endpoints accept a `Bearer dk_...` API key (create one in /api-keys); unauthenticated requests use the guest tier and are rate-limited per IP.",
    "contact": { "name": "Dokven", "url": "https://dokven.app" }
  },
  "servers": [
    { "url": "https://dokven.app", "description": "Production" }
  ],
  "tags": [
    { "name": "Scans", "description": "Run a module or the full stack against a URL" },
    { "name": "Test Plans", "description": "Generate, retrieve, and execute test plans" },
    { "name": "Webhooks", "description": "Manage outbound webhook subscriptions" },
    { "name": "Monitoring", "description": "Watched URLs that auto-scan on a schedule" },
    { "name": "Account", "description": "Account, billing, and run history" }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "dk_..." }
    },
    "schemas": {
      "CheckResult": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "status": { "type": "string", "enum": ["pass", "warn", "fail", "info"] },
          "message": { "type": "string" },
          "details": { "type": "string", "nullable": true },
          "category": { "type": "string", "nullable": true }
        },
        "required": ["id", "name", "status", "message"]
      },
      "ScanRequest": {
        "type": "object",
        "properties": {
          "url": { "type": "string", "format": "uri" }
        },
        "required": ["url"]
      },
      "ScanResponse": {
        "type": "object",
        "properties": {
          "runId": { "type": "string", "nullable": true },
          "url": { "type": "string" },
          "feature": { "type": "string" },
          "score": { "type": "integer", "minimum": 0, "maximum": 100 },
          "grade": { "type": "string", "enum": ["A", "B", "C", "D", "F"] },
          "summary": { "type": "string" },
          "recommendations": { "type": "array", "items": { "type": "string" } },
          "checks": { "type": "array", "items": { "$ref": "#/components/schemas/CheckResult" } },
          "tokenCost": { "type": "integer" },
          "tokenBalance": { "type": "integer" },
          "cached": { "type": "boolean" },
          "timestamp": { "type": "string", "format": "date-time" }
        }
      },
      "FullStackScanResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ScanResponse" },
          {
            "type": "object",
            "properties": {
              "modules": {
                "type": "object",
                "properties": {
                  "seo": { "$ref": "#/components/schemas/ModuleSlice" },
                  "security": { "$ref": "#/components/schemas/ModuleSlice" },
                  "performance": { "$ref": "#/components/schemas/ModuleSlice" },
                  "accessibility": { "$ref": "#/components/schemas/ModuleSlice" },
                  "copy": { "$ref": "#/components/schemas/ModuleSlice" }
                }
              },
              "crosswalk": {
                "type": "array",
                "items": { "$ref": "#/components/schemas/CrosswalkInsight" }
              }
            }
          }
        ]
      },
      "ModuleSlice": {
        "type": "object",
        "properties": {
          "score": { "type": "integer" },
          "grade": { "type": "string" },
          "checks": { "type": "array", "items": { "$ref": "#/components/schemas/CheckResult" } }
        }
      },
      "CrosswalkInsight": {
        "type": "object",
        "properties": {
          "title": { "type": "string" },
          "rootCause": { "type": "string" },
          "affectedModules": { "type": "array", "items": { "type": "string" } },
          "recommendation": { "type": "string" },
          "severity": { "type": "string", "enum": ["high", "medium", "low"] }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" }
        },
        "required": ["error"]
      }
    }
  },
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/api/scan/all": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run a Full Stack scan (SEO + security + performance + accessibility + copy + AI crosswalk).",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } }
        },
        "responses": {
          "200": { "description": "Scan complete", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FullStackScanResponse" } } } },
          "400": { "description": "Invalid URL", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "402": { "description": "Insufficient tokens", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit exceeded", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/seo-audit": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run SEO Audit",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/security": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run Security Headers scan",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/performance": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run Performance scan",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/accessibility": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run Accessibility Check",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/copy-testing": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run Copy Testing",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/responsive-testing": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run Responsive Testing",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/test-api": {
      "post": {
        "tags": ["Scans"],
        "summary": "Run API Health Check",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanResponse" } } } } }
      }
    },
    "/api/tag-audit/scan": {
      "post": {
        "tags": ["Scans"],
        "summary": "Start a Tag & Event audit",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ScanRequest" } } } },
        "responses": { "200": { "description": "Scan accepted with a polling scanId.", "content": { "application/json": { "schema": { "type": "object", "properties": { "scanId": { "type": "string" } } } } } } }
      }
    },
    "/api/test-plans/generate": {
      "post": {
        "tags": ["Test Plans"],
        "summary": "Generate a test plan from a live URL",
        "responses": { "200": { "description": "Generated test plan." } }
      }
    },
    "/api/test-plans/case-runs": {
      "get": {
        "tags": ["Test Plans"],
        "summary": "List per-case run history for a plan",
        "parameters": [{ "name": "planId", "in": "query", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Array of CaseRun records." } }
      },
      "post": {
        "tags": ["Test Plans"],
        "summary": "Record a per-case run result (any module can write back here)",
        "responses": { "200": { "description": "Recorded." } }
      }
    },
    "/api/test-plans/run-case": {
      "post": {
        "tags": ["Test Plans"],
        "summary": "Convert a test case into Playwright steps and submit to the automation runner",
        "responses": { "200": { "description": "jobId returned; stream via /api/automation/stream." } }
      }
    },
    "/api/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List your webhook subscriptions",
        "responses": { "200": { "description": "Array of subscriptions." } }
      },
      "post": {
        "tags": ["Webhooks"],
        "summary": "Create a Slack / Discord / generic webhook subscription",
        "responses": { "200": { "description": "Created (returns the signing secret)." } }
      }
    },
    "/api/watched-urls": {
      "get": {
        "tags": ["Monitoring"],
        "summary": "List URLs you're watching",
        "responses": { "200": { "description": "Array of watched URLs." } }
      },
      "post": {
        "tags": ["Monitoring"],
        "summary": "Watch a URL for daily/weekly regression alerts",
        "responses": { "200": { "description": "Created." } }
      }
    },
    "/api/account/me": {
      "get": {
        "tags": ["Account"],
        "summary": "Logged-in user + plan + token balance",
        "responses": { "200": { "description": "Account snapshot." } }
      }
    },
    "/api/runs/{id}/share": {
      "post": {
        "tags": ["Account"],
        "summary": "Toggle the public share link for a run",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": { "200": { "description": "Share token + URL." } }
      }
    }
  }
}
