{
  "openapi": "3.0.3",
  "info": {
    "title": "sealverity.ai API",
    "version": "1.0.0",
    "description": "Deepfake and manipulation detection API. Scores are probabilities, not proof; flagged results require human review. Authenticate with an organisation API key or personal token in the x-api-key header."
  },
  "servers": [{ "url": "https://lavishoverify.lovable.app" }],
  "components": {
    "securitySchemes": { "ApiKey": { "type": "apiKey", "in": "header", "name": "x-api-key" } },
    "schemas": {
      "Error": { "type": "object", "properties": { "error": { "type": "string" } } },
      "CheckResult": {
        "type": "object",
        "properties": {
          "artifact_id": { "type": "string", "format": "uuid" },
          "score": { "type": "number", "nullable": true, "minimum": 0, "maximum": 100 },
          "band": { "type": "string", "example": "High agreement" },
          "agreement": { "type": "string", "nullable": true, "enum": ["high", "moderate", "disagree"] },
          "status": { "type": "string", "enum": ["flagged", "inconclusive", "below", "error"] },
          "threshold": { "type": "number" },
          "detectors_used": { "type": "integer" },
          "detectors_total": { "type": "integer" },
          "media_type": { "type": "string", "enum": ["image", "video", "audio"] },
          "file_name": { "type": "string" },
          "link": { "type": "string", "format": "uri" },
          "note": { "type": "string" }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "description": "Body of every outbound webhook (json format). Verify X-Lavisho-Signature = 'sha256=' + hex(HMAC-SHA256(secret, X-Lavisho-Timestamp + '.' + rawBody)).",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "event": { "type": "string", "enum": ["analysis.completed", "analysis.flagged", "alert.raised", "case.created", "report.issued", "kyc.completed", "call.alert", "test"] },
          "org_id": { "type": "string", "format": "uuid" },
          "created_at": { "type": "string", "format": "date-time" },
          "data": { "type": "object", "additionalProperties": true }
        }
      }
    }
  },
  "security": [{ "ApiKey": [] }],
  "paths": {
    "/api/public/v1/check": {
      "post": {
        "summary": "Check a media file or link with the detector ensemble",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri", "description": "Direct media URL or a web page with og:image/og:video" }, "page_url": { "type": "string" } } } },
            "multipart/form-data": { "schema": { "type": "object", "required": ["file"], "properties": { "file": { "type": "string", "format": "binary" } } } }
          }
        },
        "responses": {
          "200": { "description": "Result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckResult" } } } },
          "401": { "description": "Invalid token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Blocked by sovereign mode" },
          "422": { "description": "Unsupported or unreachable media" },
          "429": { "description": "Quota exceeded" }
        }
      }
    },
    "/api/public/v1/me": {
      "get": { "summary": "Validate a token", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "organisation": { "type": "string" }, "token": { "type": "string" }, "personal": { "type": "boolean" } } } } } }, "401": { "description": "Invalid token" } } }
    },
    "/api/public/v1/validate": {
      "post": {
        "summary": "Real-time text validation",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["media_type"], "properties": { "media_type": { "type": "string", "enum": ["text", "document", "image", "video", "audio"] }, "text": { "type": "string", "maxLength": 50000 }, "sha256": { "type": "string" }, "reference": { "type": "string" } } } } } },
        "responses": { "200": { "description": "Result" }, "401": { "description": "Invalid key" }, "422": { "description": "No live detector" } }
      }
    },
    "/api/public/v1/voice/check": {
      "post": {
        "summary": "Call-centre synthetic-voice check (audio chunk or streaming URL)",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "audio": { "type": "string", "format": "binary" } } } }, "application/json": { "schema": { "type": "object", "properties": { "audio_base64": { "type": "string" }, "url": { "type": "string", "format": "uri" } } } } } },
        "responses": { "200": { "description": "Synthetic-voice score" }, "401": { "description": "Invalid key" } }
      }
    },
    "/api/public/v1/kyc/check": {
      "post": {
        "summary": "Identity document + selfie check",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "document_front": { "type": "string", "format": "binary" }, "document_back": { "type": "string", "format": "binary" }, "selfie": { "type": "string", "format": "binary" }, "reference": { "type": "string" }, "callback_url": { "type": "string", "format": "uri" } } } } } },
        "responses": { "200": { "description": "Pass / Review / Reject decision with reasons" }, "401": { "description": "Invalid key" } }
      }
    }
  },
  "x-webhooks": {
    "event": { "post": { "summary": "Outbound event", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEvent" } } } }, "responses": { "2XX": { "description": "Acknowledged. Non-2xx is retried after 1, 5, 30, 120 and 720 minutes." } } } }
  }
}
