{
  "openapi": "3.1.0",
  "info": {
    "title": "Decision Labs Public API",
    "version": "1.0.0",
    "description": "Free, public API for U.S. electoral data: historical election results, 2026 polling, race ratings, swing analysis, prediction-market snapshots, and bulk exports. No authentication. CORS enabled for all origins. Stability policy: v1 — breaking changes are announced on https://decisionlabs.ai/docs/api at least 30 days in advance; additive changes may ship at any time.",
    "license": {
      "name": "Data: CC BY 4.0 (attribute \"Decision Labs (decisionlabs.ai)\"). Code: MIT.",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "contact": { "url": "https://decisionlabs.ai/contact" }
  },
  "servers": [{ "url": "https://decisionlabs.ai" }],
  "paths": {
    "/api/elections/{year}": {
      "get": {
        "summary": "All state results for a presidential election year",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "description": "Election year (1976-2024, divisible by 4)", "schema": { "type": "integer", "example": 2024 } }
        ],
        "responses": {
          "200": {
            "description": "National summary plus per-state results",
            "content": { "application/json": { "example": { "year": 2024, "national": { "winner": "...", "ev": {}, "popular_vote": {} }, "states": [{ "abbr": "PA", "name": "Pennsylvania", "ev_count": 19, "winner": "...", "margin": 1.7, "candidates": [] }] } } }
          },
          "400": { "description": "Invalid year" },
          "404": { "description": "No data for year" }
        }
      }
    },
    "/api/elections/{year}/{state}": {
      "get": {
        "summary": "Detailed results for one state in one election",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "schema": { "type": "integer", "example": 2024 } },
          { "name": "state", "in": "path", "required": true, "description": "State abbreviation", "schema": { "type": "string", "example": "PA" } }
        ],
        "responses": {
          "200": { "description": "Single-state detail", "content": { "application/json": { "example": { "year": 2024, "state": { "abbr": "PA", "name": "Pennsylvania", "ev_count": 19, "margin": 1.7, "candidates": [] } } } } },
          "404": { "description": "Year or state not found" }
        }
      }
    },
    "/api/states/{abbr}/history": {
      "get": {
        "summary": "All presidential results for a state since 1976",
        "parameters": [
          { "name": "abbr", "in": "path", "required": true, "schema": { "type": "string", "example": "PA" } }
        ],
        "responses": {
          "200": { "description": "State election history", "content": { "application/json": { "example": { "abbr": "PA", "name": "Pennsylvania", "region": "Northeast", "ev_history": [], "elections": [] } } } },
          "404": { "description": "State not found" }
        }
      }
    },
    "/api/polls": {
      "get": {
        "summary": "Recent polls with optional filtering",
        "parameters": [
          { "name": "state", "in": "query", "description": "State abbreviation or \"national\"", "schema": { "type": "string" } },
          { "name": "days", "in": "query", "description": "Only polls from the last N days", "schema": { "type": "integer" } },
          { "name": "min_rating", "in": "query", "description": "Minimum pollster rating (A+ through C-)", "schema": { "type": "string" } },
          { "name": "pollster", "in": "query", "description": "Pollster name, partial match", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Filtered poll list", "content": { "application/json": { "example": { "polls": [], "meta": { "count": 0, "filters": {} } } } } },
          "404": { "description": "Polling data not available" }
        }
      }
    },
    "/api/polls/average": {
      "get": {
        "summary": "Computed polling average with adjustable parameters",
        "parameters": [
          { "name": "state", "in": "query", "description": "State abbreviation or \"national\"", "schema": { "type": "string" } },
          { "name": "half_life", "in": "query", "description": "Recency half-life in days (default 14)", "schema": { "type": "integer", "default": 14 } },
          { "name": "min_rating", "in": "query", "description": "Minimum pollster rating (default C-)", "schema": { "type": "string", "default": "C-" } }
        ],
        "responses": {
          "200": { "description": "Weighted polling average", "content": { "application/json": { "example": { "average": {}, "methodology": {}, "polls_included": [] } } } }
        }
      }
    },
    "/api/ratings/{year}": {
      "get": {
        "summary": "Third-party race ratings for the 2026 cycle (Cook, Sabato, Inside Elections)",
        "description": "Values are null until verified by automated sourcing.",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "schema": { "type": "integer", "example": 2026 } }
        ],
        "responses": {
          "200": { "description": "Race ratings", "content": { "application/json": { "example": { "year": 2026, "source_status": "...", "last_verified": "...", "raters": [], "ratings": [{ "raceId": "pa-gov-2026", "abbr": "PA", "state": "Pennsylvania", "office": "governor", "cook": null, "sabato": null, "inside_elections": null }] } } } },
          "404": { "description": "Ratings data not available" }
        }
      }
    },
    "/api/swing": {
      "get": {
        "summary": "Swing analysis between two election years",
        "parameters": [
          { "name": "from_year", "in": "query", "schema": { "type": "integer", "default": 2020 } },
          { "name": "to_year", "in": "query", "schema": { "type": "integer", "default": 2024 } }
        ],
        "responses": {
          "200": { "description": "National and per-state swing", "content": { "application/json": { "example": { "from_year": 2016, "to_year": 2020, "national_swing": 0, "states": [] } } } }
        }
      }
    },
    "/api/governor/{year}": {
      "get": {
        "summary": "Governor election results for a year",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "description": "Even year, 1976-2024", "schema": { "type": "integer", "example": 2022 } }
        ],
        "responses": {
          "200": { "description": "Governor results" },
          "400": { "description": "Invalid year" },
          "404": { "description": "No data for year" }
        }
      }
    },
    "/api/senate/{year}": {
      "get": {
        "summary": "Senate election results for a year",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "description": "Even year, 1976-2024", "schema": { "type": "integer", "example": 2022 } }
        ],
        "responses": {
          "200": { "description": "Senate results" },
          "400": { "description": "Invalid year" },
          "404": { "description": "No data for year" }
        }
      }
    },
    "/api/house/{year}": {
      "get": {
        "summary": "House election results for a year",
        "parameters": [
          { "name": "year", "in": "path", "required": true, "description": "Even year, 1976-2024", "schema": { "type": "integer", "example": 2022 } }
        ],
        "responses": {
          "200": { "description": "House results" },
          "400": { "description": "Invalid year" },
          "404": { "description": "No data for year" }
        }
      }
    },
    "/api/prediction-markets": {
      "get": {
        "summary": "Live prediction-market snapshot for a 2026 race",
        "parameters": [
          { "name": "raceId", "in": "query", "required": true, "description": "Race id matching ^[a-z]{2}-(gov|sen|national)-2026$", "schema": { "type": "string", "example": "ca-gov-2026" } }
        ],
        "responses": {
          "200": { "description": "Snapshot of Polymarket/Kalshi prices plus 7-day trends", "content": { "application/json": { "example": { "available": true, "snapshot": { "fetchedAt": "...", "platforms": { "polymarket": [], "kalshi": [] } }, "trends": {} } } } },
          "400": { "description": "Invalid raceId" }
        }
      }
    },
    "/api/export": {
      "get": {
        "summary": "Bulk export of presidential results as CSV or JSON",
        "parameters": [
          { "name": "year", "in": "query", "required": true, "schema": { "type": "integer", "example": 2024 } },
          { "name": "state", "in": "query", "description": "Filter to one state", "schema": { "type": "string" } },
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json", "csv"], "default": "json" } }
        ],
        "responses": {
          "200": {
            "description": "Flattened per-state rows as a file download",
            "content": {
              "application/json": { "example": [{ "year": 2024, "state": "Pennsylvania", "abbreviation": "PA", "electoral_votes": 19, "winner": "...", "dem_pct": 0, "rep_pct": 0, "margin": 0, "flipped": false }] },
              "text/csv": { "example": "year,state,abbreviation,electoral_votes,winner,..." }
            }
          },
          "400": { "description": "Missing or invalid year/state" },
          "404": { "description": "No data for year" }
        }
      }
    },
    "/api/export/polls": {
      "get": {
        "summary": "Bulk export of ALL 2026 race polls as JSON or CSV",
        "description": "JSON returns full poll objects with per-candidate results keyed by candidate slug. CSV is tidy format: one row per (poll, candidate) pair. Best-effort rate limit: 30 requests/minute per IP.",
        "parameters": [
          { "name": "format", "in": "query", "schema": { "type": "string", "enum": ["json", "csv"], "default": "json" } },
          { "name": "race", "in": "query", "description": "Filter to one race id matching ^[a-z]{2}-[a-z-]+-\\d{4}$", "schema": { "type": "string", "example": "ca-gov-2026" } }
        ],
        "responses": {
          "200": {
            "description": "All 2026 polls (newest first) as a file download",
            "content": {
              "application/json": {
                "example": {
                  "meta": { "count": 1, "races": 70, "race": null, "generatedAt": "2026-06-10T00:00:00Z", "license": "CC BY 4.0 — attribute \"Decision Labs (decisionlabs.ai)\"" },
                  "polls": [{ "raceId": "ca-gov-2026", "date": "2025-09-16", "pollster": "Emerson", "grade": "A-", "sampleSize": 1000, "population": "registered_voters", "marginOfError": 3, "partisan": null, "results": { "katie-porter": 16, "steve-hilton": 10 }, "sourceUrl": "https://..." }]
                }
              },
              "text/csv": { "example": "race_id,date,pollster,grade,sample_size,population,margin_of_error,partisan,candidate,pct,source_url" }
            }
          },
          "400": { "description": "Invalid race parameter" },
          "404": { "description": "Race not found" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    }
  }
}
