{
 "openapi": "3.1.0",
 "info": {
  "title": "Arcvane Visibility public API",
  "version": "1.0.0",
  "description": "Run a free preview of a public website and receive results as they are produced. Results are labelled states (Find, Understand, Use, AI answers), never a single score.",
  "contact": {
   "name": "Arcvane Labs",
   "email": "hello@arcvanelabs.com"
  }
 },
 "servers": [
  {
   "url": "https://visibility.arcvanelabs.com"
  }
 ],
 "paths": {
  "/api/v1/health": {
   "get": {
    "operationId": "health",
    "summary": "Service status",
    "responses": {
     "200": {
      "description": "OK",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "ok": {
           "type": "boolean"
          },
          "api": {
           "type": "string"
          },
          "time": {
           "type": "string",
           "format": "date-time"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/scans/stream": {
   "get": {
    "operationId": "streamScan",
    "summary": "Run a free preview and stream results (Server-Sent Events)",
    "description": "Starts a check of a public website and streams one event per finished result. Events: `accepted`, `scan_started`, `check`, `page`, `tree`, `summary`, `scan_complete`, `scan_error`. Each `data` field is JSON. Only public http/https websites on standard ports are accepted.",
    "parameters": [
     {
      "name": "url",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "https://example.com/"
     },
     {
      "name": "market",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "US",
        "GB",
        "CA",
        "AU",
        "IE"
       ],
       "default": "US"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Event stream",
      "content": {
       "text/event-stream": {
        "schema": {
         "type": "string"
        },
        "example": "id: 3\nevent: check\ndata: {\"id\":\"robots_ai\",\"layer\":\"find\",\"state\":\"ok\",\"label\":\"All allowed\",\"title\":\"AI crawler rules for this page\",\"detail\":\"...\",\"t\":13}\n\n"
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "description": "Too many checks from your network; see the Retry-After header",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "503": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/api/v1/scans/{id}": {
   "get": {
    "operationId": "getScan",
    "summary": "Get a saved preview (kept 30 days)",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "pattern": "^scn_[a-z0-9]{8,24}$"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Saved result",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ScanResult"
        }
       }
      }
     },
     "404": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Check": {
    "type": "object",
    "required": [
     "id",
     "layer",
     "state",
     "label",
     "title",
     "detail",
     "t"
    ],
    "properties": {
     "id": {
      "type": "string",
      "examples": [
       "price_text"
      ]
     },
     "layer": {
      "type": "string",
      "enum": [
       "find",
       "understand",
       "use",
       "interfaces",
       "ai"
      ]
     },
     "state": {
      "type": "string",
      "enum": [
       "ok",
       "warn",
       "bad",
       "na",
       "info"
      ]
     },
     "label": {
      "type": "string",
      "examples": [
       "Possibly image only"
      ]
     },
     "title": {
      "type": "string"
     },
     "detail": {
      "type": "string"
     },
     "fix": {
      "type": [
       "string",
       "null"
      ]
     },
     "evidence": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "page": {
      "type": "string",
      "format": "uri"
     },
     "t": {
      "type": "integer",
      "description": "Milliseconds since the scan started"
     }
    }
   },
   "State": {
    "type": "object",
    "properties": {
     "state": {
      "type": "string",
      "enum": [
       "ok",
       "warn",
       "bad",
       "na",
       "info"
      ]
     },
     "label": {
      "type": "string"
     },
     "note": {
      "type": "string"
     }
    }
   },
   "Summary": {
    "type": "object",
    "properties": {
     "find": {
      "$ref": "#/components/schemas/State"
     },
     "understand": {
      "$ref": "#/components/schemas/State"
     },
     "use": {
      "$ref": "#/components/schemas/State"
     },
     "ai": {
      "$ref": "#/components/schemas/State"
     }
    }
   },
   "ScanResult": {
    "type": "object",
    "properties": {
     "scanId": {
      "type": "string"
     },
     "target": {
      "type": "string",
      "format": "uri"
     },
     "market": {
      "type": "string"
     },
     "startedAt": {
      "type": "string",
      "format": "date-time"
     },
     "durationMs": {
      "type": "integer"
     },
     "pagesChecked": {
      "type": "array",
      "items": {
       "type": "string",
       "format": "uri"
      }
     },
     "checks": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Check"
      }
     },
     "summary": {
      "$ref": "#/components/schemas/Summary"
     }
    }
   },
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string",
        "examples": [
         "invalid_url",
         "blocked_address",
         "rate_limited"
        ]
       },
       "message": {
        "type": "string"
       }
      }
     }
    }
   }
  },
  "responses": {
   "Error": {
    "description": "Error",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  }
 }
}