{
  "openapi": "3.1.0",
  "info": {
    "title": "hantavirusmap.io public dataset",
    "version": "1.0.0",
    "summary": "Open, source-cited dataset of every documented hantavirus outbreak from 1993 to the present.",
    "description": "Public-good dataset published under CC-BY-4.0. LLM agents and downstream tooling can poll /data/outbreaks.json for the full bundle, or per-event endpoints for individual records.\n\nNo authentication required. Permissive CORS. Educational use only — not medical advice.",
    "termsOfService": "https://hantavirusmap.io/disclaimer",
    "contact": {
      "name": "Micky Dollimore",
      "url": "https://mickydollimore.com",
      "email": "micky@wizedwarlock.com"
    },
    "license": {
      "name": "CC-BY-4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    }
  },
  "servers": [
    {
      "url": "https://hantavirusmap.io",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "outbreaks", "description": "Outbreak records — the canonical data product." },
    { "name": "manifests", "description": "Crawler-facing manifests." }
  ],
  "paths": {
    "/data/outbreaks.json": {
      "get": {
        "tags": ["outbreaks"],
        "operationId": "getOutbreaks",
        "summary": "All outbreak records as a single bundle",
        "description": "Returns every published outbreak record plus aggregate statistics, the dataset version, generation timestamp, and license metadata. The single citable endpoint LLM agents and journalists reference.",
        "responses": {
          "200": {
            "description": "Bundle response",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OutbreakBundle" }
              }
            }
          }
        }
      }
    },
    "/raw/event/{id}.md": {
      "get": {
        "tags": ["outbreaks"],
        "operationId": "getEventMarkdown",
        "summary": "Plain-markdown shadow of a single event",
        "description": "Returns the event in Markdown — preferred ingestion format for LLMs. Includes YAML front-matter with the same machine-readable fields as the JSON bundle.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "pattern": "^[0-9]{4}-[a-z0-9-]+$" },
            "description": "Outbreak ID, format `{year}-{kebab-slug}` (e.g. `2026-mv-hondius`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Markdown body",
            "content": {
              "text/markdown": { "schema": { "type": "string" } }
            }
          },
          "404": {
            "description": "No event with that ID is published."
          }
        }
      }
    },
    "/event/{id}": {
      "get": {
        "tags": ["outbreaks"],
        "operationId": "getEventHtml",
        "summary": "Human-facing event page (HTML)",
        "description": "Source-cited HTML page for a single event with embedded JSON-LD (Article + ClaimReview).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": { "type": "string", "pattern": "^[0-9]{4}-[a-z0-9-]+$" }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML page",
            "content": { "text/html": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": ["manifests"],
        "operationId": "getLlmsTxt",
        "summary": "LLM crawler manifest (proposed llms.txt standard)",
        "responses": {
          "200": {
            "description": "Plain-text manifest",
            "content": { "text/plain": { "schema": { "type": "string" } } }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "tags": ["manifests"],
        "operationId": "getSitemap",
        "summary": "Full URL sitemap",
        "responses": {
          "200": {
            "description": "XML sitemap",
            "content": { "application/xml": { "schema": { "type": "string" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "OutbreakBundle": {
        "type": "object",
        "required": ["version", "license", "generated_at", "stats", "outbreaks"],
        "properties": {
          "version": { "type": "integer", "example": 1 },
          "license": { "type": "string", "example": "CC-BY-4.0" },
          "license_url": { "type": "string", "format": "uri" },
          "attribution": { "type": "string", "example": "hantavirusmap.io" },
          "citation": { "type": "string", "example": "hantavirusmap.io/data/outbreaks.json (CC-BY-4.0)" },
          "generated_at": { "type": "string", "format": "date-time" },
          "stats": { "$ref": "#/components/schemas/AggregateStats" },
          "outbreaks": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Outbreak" }
          }
        }
      },
      "AggregateStats": {
        "type": "object",
        "properties": {
          "total_events": { "type": "integer" },
          "total_confirmed": { "type": "integer" },
          "total_suspected": { "type": "integer" },
          "total_deaths": { "type": "integer" },
          "countries": { "type": "array", "items": { "type": "string" } },
          "pathogens": { "type": "array", "items": { "type": "string" } },
          "syndromes": { "type": "array", "items": { "type": "string", "enum": ["HPS", "HFRS"] } }
        }
      },
      "Outbreak": {
        "type": "object",
        "required": ["id", "pathogen", "syndrome", "country_iso2", "location", "start_date", "cases", "summary", "sources", "status", "confidence"],
        "properties": {
          "id": {
            "type": "string",
            "pattern": "^[0-9]{4}-[a-z0-9-]+$",
            "example": "2026-mv-hondius"
          },
          "pathogen": {
            "type": "string",
            "enum": ["andes", "sin-nombre", "hantaan", "puumala", "seoul", "dobrava", "choclo", "laguna-negra", "bayou", "black-creek-canal", "tula", "thailand"]
          },
          "syndrome": { "type": "string", "enum": ["HPS", "HFRS"] },
          "country_iso2": { "type": "string", "minLength": 2, "maxLength": 4 },
          "countries_affected": {
            "type": "array",
            "items": { "type": "string", "minLength": 2, "maxLength": 2 }
          },
          "region": { "type": "string" },
          "location": {
            "type": "object",
            "required": ["name", "lat", "lng"],
            "properties": {
              "name": { "type": "string" },
              "lat": { "type": "number", "minimum": -90, "maximum": 90 },
              "lng": { "type": "number", "minimum": -180, "maximum": 180 },
              "precision": { "type": "string", "enum": ["exact", "approximate", "estimated"] }
            }
          },
          "start_date": { "type": "string", "format": "date" },
          "end_date": { "type": "string", "format": "date", "nullable": true },
          "cases": {
            "type": "object",
            "properties": {
              "confirmed": { "type": "integer", "minimum": 0 },
              "suspected": { "type": "integer", "minimum": 0 },
              "deaths": { "type": "integer", "minimum": 0 },
              "last_updated": { "type": "string", "format": "date" }
            }
          },
          "summary": { "type": "string" },
          "significance": { "type": "string" },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["url", "title", "publisher", "tier", "accessed"],
              "properties": {
                "url": { "type": "string", "format": "uri" },
                "title": { "type": "string" },
                "publisher": { "type": "string" },
                "tier": { "type": "integer", "minimum": 1, "maximum": 4 },
                "accessed": { "type": "string", "format": "date" }
              }
            }
          },
          "status": { "type": "string", "enum": ["active", "concluded", "historical"] },
          "confidence": { "type": "string", "enum": ["verified", "preliminary", "unverified"] }
        }
      }
    }
  }
}
