{
  "openapi": "3.0.3",
  "info": {
    "title": "Citation Safe Verification API",
    "version": "1.0.0",
    "description": "Verifies legal citations against primary sources. Three checks per citation — existence (deterministic, against CourtListener's opinion database), quote match (deterministic), and proposition support (LLM-assisted, paid tiers only). Results are always three-state: VERIFIED, UNCONFIRMED, or NOT FOUND — never a bare true/false. Live accuracy published at https://citationsafe.com/quality.\n\nStatus note (honest, as of this writing): this spec documents the API surface that exists today in production (POST /api/verify). A dedicated versioned batch endpoint (/v1/verify) with API-key auth and usage metering is roadmapped for the Enterprise API tier and is not live yet — do not build integrations against paths not listed below.",
    "contact": {
      "name": "Citation Safe Support",
      "email": "support@citationsafe.com",
      "url": "https://citationsafe.com/contact"
    },
    "termsOfService": "https://citationsafe.com/terms",
    "license": {
      "name": "Proprietary — API use subject to Citation Safe Terms of Service"
    }
  },
  "servers": [
    { "url": "https://citationsafe.com", "description": "Production" }
  ],
  "tags": [
    { "name": "verification", "description": "Citation verification" }
  ],
  "paths": {
    "/api/verify": {
      "post": {
        "tags": ["verification"],
        "summary": "Verify citations in a document",
        "description": "Accepts either raw text/JSON or a multipart file upload (PDF/DOCX), extracts citations, and runs the 3-layer verification engine. Anonymous callers are always served the free tier regardless of any client-supplied tier value — tier is resolved server-side from authenticated identity or billing account, never trusted from the request body for paid-feature gating.",
        "operationId": "verifyDocument",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/VerifyJsonRequest" },
              "example": { "text": "See Smith v. Jones, 123 F.3d 456, 460 (9th Cir. 2020).", "email": "you@firm.com" }
            },
            "multipart/form-data": {
              "schema": { "$ref": "#/components/schemas/VerifyFileRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification completed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/VerifyResponse" }
              }
            }
          },
          "400": {
            "description": "Bad request — invalid JSON, no text provided, unparseable file, or file exceeds 15MB",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
          },
          "402": {
            "description": "Free-tier monthly quota exhausted — upgrade required",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaywallResponse" } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Optional. Supabase Auth JWT for authenticated users — enables /dashboard history and durable per-user billing/usage tracking. Unauthenticated requests fall back to guest-email usage tracking (JSON body `email` field) or, with no identity at all, are served the free tier with no persistent usage counting."
      }
    },
    "schemas": {
      "VerifyJsonRequest": {
        "type": "object",
        "required": ["text"],
        "properties": {
          "text": { "type": "string", "maxLength": 64000, "description": "Raw text containing one or more legal citations." },
          "email": { "type": "string", "format": "email", "description": "Guest identity for free-tier usage tracking when not authenticated via Bearer token." },
          "tier": { "type": "string", "enum": ["free", "one_off", "solo", "professional", "firm"], "description": "Advisory only for unauthenticated requests — actual tier is always resolved server-side from the account/billing record, never trusted from this field for paid-feature gating." }
        }
      },
      "VerifyFileRequest": {
        "type": "object",
        "required": ["file"],
        "properties": {
          "file": { "type": "string", "format": "binary", "description": "PDF or DOCX, max 15MB." },
          "email": { "type": "string", "format": "email" },
          "tier": { "type": "string", "enum": ["free", "one_off", "solo", "professional", "firm"] }
        }
      },
      "CitationResult": {
        "type": "object",
        "properties": {
          "citeText": { "type": "string", "example": "Smith v. Jones, 123 F.3d 456, 460 (9th Cir. 2020)" },
          "existenceResult": { "type": "string", "enum": ["verified", "unconfirmed", "not_found", "outside_coverage", "source_unavailable"] },
          "quoteResult": { "type": "string", "enum": ["verified", "unconfirmed", "not_found", "outside_coverage", "source_unavailable", "not_applicable"] },
          "propositionResult": { "type": "string", "enum": ["verified", "unconfirmed", "not_found", "not_applicable"], "description": "Only populated when layer3Enabled is true (paid tiers with proposition text supplied)." },
          "sourceUrl": { "type": "string", "format": "uri", "nullable": true },
          "confidence": { "type": "number", "nullable": true },
          "checkedSources": { "type": "array", "items": { "type": "string" } }
        }
      },
      "VerifyResponse": {
        "type": "object",
        "properties": {
          "verificationId": { "type": "string", "description": "Unique ID; also resolvable at https://citationsafe.com/v/{verificationId} as a public certification lookup page." },
          "citationsFound": { "type": "integer" },
          "results": { "type": "array", "items": { "$ref": "#/components/schemas/CitationResult" } },
          "tier": { "type": "string" },
          "layer3Enabled": { "type": "boolean" },
          "engineVersion": { "type": "string" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": { "error": { "type": "string" } }
      },
      "PaywallResponse": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "example": "paywall" },
          "message": { "type": "string" },
          "used": { "type": "integer" },
          "limit": { "type": "integer" }
        }
      }
    }
  },
  "security": [{ "bearerAuth": [] }, {}]
}
