{
  "openapi": "3.1.0",
  "info": {
    "title": "AI Policy Radar API",
  "version": "1.2.0",
    "description": "Read-only policy data and generated policy research from AI Policy Radar. Policy activity data and research; not legal advice.",
    "contact": {
      "name": "AI Policy Radar",
      "email": "hello@aipolicyradar.com",
      "url": "https://aipolicyradar.com/developers/"
    },
    "license": {
      "name": "AI Policy Radar API Terms",
      "identifier": "LicenseRef-AIPolicyRadar-API-1.0",
      "url": "https://aipolicyradar.com/developers/#terms"
    }
  },
  "servers": [
    {
      "url": "https://api.aipolicyradar.com",
      "description": "Production"
    }
  ],
  "tags": [
    { "name": "Metadata" },
    { "name": "Jurisdictions" },
    { "name": "Measures" },
    { "name": "Changes" },
    { "name": "Answers" },
    { "name": "Access" }
  ],
  "paths": {
    "/v1/meta": {
      "get": {
        "tags": ["Metadata"],
        "operationId": "getMeta",
        "summary": "Get release metadata, coverage counts, categories, and sectors",
        "responses": {
          "200": {
            "description": "Current API and catalogue metadata",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MetaResponse" } } }
          }
        }
      }
    },
    "/v1/jurisdictions": {
      "get": {
        "tags": ["Jurisdictions"],
        "operationId": "listJurisdictions",
        "summary": "List tracked global jurisdictions and US states",
        "responses": {
          "200": {
            "description": "Tracked jurisdictions",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JurisdictionListResponse" } } }
          }
        }
      }
    },
    "/v1/jurisdictions/{code}": {
      "get": {
        "tags": ["Jurisdictions"],
        "operationId": "getJurisdiction",
        "summary": "Get one jurisdiction profile and measure counts",
        "parameters": [
          { "name": "code", "in": "path", "required": true, "schema": { "type": "string" }, "example": "KR" }
        ],
        "responses": {
          "200": {
            "description": "Jurisdiction profile and measure counts. Global profiles may include a maintained narrative baseline; US state profiles currently expose measure-level coverage.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JurisdictionResponse" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/measures/{id}": {
      "get": {
        "tags": ["Measures"],
        "operationId": "getMeasure",
        "summary": "Get one tracked measure",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "example": "m:US-CA:SB11" }
        ],
        "responses": {
          "200": {
            "description": "Tracked measure with official-source URL",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MeasureResponse" } } }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/search": {
      "post": {
        "tags": ["Measures"],
        "operationId": "searchMeasures",
        "summary": "Search tracked measures",
        "description": "At least one substantive query or filter is required. Results use opaque cursor pagination. The maximum page size is 50.",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }
        },
        "responses": {
          "200": {
            "description": "Search results",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchResponse" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/QuotaExceeded" }
        }
      }
    },
    "/v1/compare": {
      "get": {
        "tags": ["Jurisdictions"],
        "operationId": "compareJurisdictions",
        "summary": "Compare two to five jurisdictions without generated prose",
        "parameters": [
          { "name": "jurisdictions", "in": "query", "required": true, "schema": { "type": "string" }, "example": "US,EU,KR" }
        ],
        "responses": {
          "200": { "description": "Deterministic baseline and category comparison" },
          "400": { "$ref": "#/components/responses/BadRequest" }
        }
      }
    },
    "/v1/changes": {
      "get": {
        "tags": ["Changes"],
        "operationId": "getChanges",
        "summary": "Get exact weekly policy movements or catalogue coverage changes",
        "description": "The default policy feed returns before-and-after movement records and excludes catalogue enrichment. Coverage changes are available only when class=coverage is requested.",
        "parameters": [
          { "name": "class", "in": "query", "required": false, "schema": { "type": "string", "enum": ["policy", "coverage"], "default": "policy" } },
          { "name": "release", "in": "query", "required": false, "description": "Weekly release date or version", "schema": { "type": "string", "default": "2026-08-27" }, "example": "2026-08-27" },
          { "name": "jurisdiction", "in": "query", "required": false, "description": "Optional jurisdiction filter", "schema": { "type": "string" }, "example": "US-CA" }
        ],
        "responses": {
          "200": { "description": "Typed change feed" },
          "429": { "$ref": "#/components/responses/QuotaExceeded" }
        }
      }
    },
    "/v1/keys/request": {
      "post": {
        "tags": ["Access"],
        "operationId": "requestDeveloperKey",
        "summary": "Request a free preview developer key",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "label": { "type": "string", "maxLength": 80 }
                }
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Key issued once in the response" },
          "409": { "description": "An active key already exists for the address" },
          "429": { "$ref": "#/components/responses/QuotaExceeded" }
        }
      }
    },
    "/v1/answers": {
      "post": {
        "tags": ["Answers"],
        "operationId": "answerPolicyQuestion",
        "summary": "Generate a policy answer",
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string", "maxLength": 120 } }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnswerRequest" } } }
        },
        "responses": {
          "200": { "description": "Grounded or researched answer with citations and quota state" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/QuotaExceeded" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Radar developer key"
      }
    },
    "schemas": {
      "Meta": {
        "type": "object",
        "required": ["api_version", "request_id", "release", "data_as_of", "information_type", "legal_advice", "official_sources_control", "notice", "attribution"],
        "properties": {
          "api_version": { "type": "string", "const": "1.2.0" },
          "request_id": { "type": "string", "format": "uuid" },
          "release": { "type": "string" },
          "data_as_of": { "type": "string", "format": "date" },
          "global_data_as_of": { "type": "string", "format": "date" },
          "us_state_data_as_of": { "type": "string", "format": "date" },
          "information_type": { "type": "string", "const": "policy_research" },
          "legal_advice": { "type": "boolean", "const": false },
          "official_sources_control": { "type": "boolean", "const": true },
          "notice": { "type": "string", "example": "Policy activity data and research; not legal advice." },
          "notice_url": { "type": "string", "format": "uri" },
          "attribution": {
            "type": "object",
            "required": ["name", "url", "text"],
            "properties": {
              "name": { "type": "string", "const": "AI Policy Radar" },
              "url": { "type": "string", "format": "uri" },
              "text": { "type": "string" }
            }
          }
        }
      },
      "MetaResponse": {
        "type": "object",
        "required": ["ok", "service", "counts", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "service": { "type": "string" },
          "counts": { "type": "object" },
          "categories": { "type": "object" },
          "sectors": { "type": "object" },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "JurisdictionListResponse": {
        "type": "object",
        "required": ["ok", "items", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/JurisdictionIndexItem" } },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "JurisdictionIndexItem": {
        "type": "object",
        "required": ["code", "name", "level", "measure_count", "baseline_available"],
        "properties": {
          "code": { "type": "string" },
          "name": { "type": "string" },
          "level": { "type": "string", "enum": ["national", "supranational", "state"] },
          "measure_count": { "type": "integer", "minimum": 0 },
          "baseline_available": { "type": "boolean" }
        }
      },
      "JurisdictionResponse": {
        "type": "object",
        "required": ["ok", "jurisdiction", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "jurisdiction": {
            "type": "object",
            "required": ["code", "name", "level", "detail_level", "measure_count", "measures_by_stage"],
            "properties": {
              "code": { "type": "string" },
              "name": { "type": "string" },
              "level": { "type": "string", "enum": ["national", "supranational", "state"] },
              "detail_level": { "type": "string", "enum": ["maintained_baseline", "measure_index"] },
              "overview": { "type": "string" },
              "instruments": { "type": "array", "items": { "type": "object" } },
              "common_questions": { "type": "array", "items": { "type": "object" } },
              "page_url": { "type": "string", "format": "uri" },
              "coverage_note": { "type": "string" },
              "measure_count": { "type": "integer", "minimum": 0 },
              "measures_by_stage": { "type": "object", "additionalProperties": { "type": "integer" } }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "Measure": {
        "type": "object",
        "required": ["id", "jurisdiction", "jurisdiction_name", "level", "title", "stage", "categories", "sectors"],
        "properties": {
          "id": { "type": "string" },
          "jurisdiction": { "type": "string" },
          "jurisdiction_name": { "type": "string" },
          "level": { "type": "string" },
          "number": { "type": ["string", "null"] },
          "title": { "type": "string" },
          "summary": { "type": "string" },
          "stage": { "type": "string" },
          "categories": { "type": "array", "items": { "type": "string" } },
          "sectors": { "type": "array", "items": { "type": "string" } },
          "date": { "type": ["string", "null"], "format": "date" },
          "official_source_url": { "type": ["string", "null"], "format": "uri" }
        }
      },
      "MeasureResponse": {
        "type": "object",
        "required": ["ok", "measure", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "measure": { "$ref": "#/components/schemas/Measure" },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "SearchRequest": {
        "type": "object",
        "properties": {
          "query": { "type": "string", "maxLength": 200 },
          "jurisdiction": { "type": "string" },
          "category": { "type": "string" },
          "stage": { "type": "string" },
          "since": { "type": "string", "format": "date" },
          "until": { "type": "string", "format": "date" },
          "limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 },
          "cursor": { "type": "string" }
        },
        "anyOf": [
          { "required": ["query"] },
          { "required": ["jurisdiction"] },
          { "required": ["category"] },
          { "required": ["stage"] },
          { "required": ["since"] },
          { "required": ["until"] }
        ]
      },
      "SearchResponse": {
        "type": "object",
        "required": ["ok", "items", "page", "resolved_scope", "filters", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": true },
          "items": { "type": "array", "items": { "$ref": "#/components/schemas/Measure" } },
          "page": {
            "type": "object",
            "required": ["count", "total", "next_cursor"],
            "properties": {
              "count": { "type": "integer" },
              "total": { "type": "integer" },
              "next_cursor": { "type": ["string", "null"] }
            }
          },
          "filters": { "type": "object" },
          "resolved_scope": {
            "type": "object",
            "required": ["collection", "jurisdictions", "category", "stage", "date_range"],
            "properties": {
              "collection": { "type": "string", "enum": ["global", "us_states", "all_tracked_records"] },
              "jurisdictions": { "type": "array", "items": { "type": "string" } },
              "category": { "type": ["string", "null"] },
              "stage": { "type": ["string", "null"] },
              "date_range": { "type": "object" }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      },
      "AnswerRequest": {
        "type": "object",
        "required": ["question"],
        "properties": {
          "question": { "type": "string", "minLength": 8, "maxLength": 600 },
          "mode": { "type": "string", "enum": ["auto", "catalogue", "live"], "default": "auto" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["ok", "error", "meta"],
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": {
            "type": "object",
            "required": ["code", "message", "contact", "contact_url"],
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "resets_at": { "type": "string", "format": "date-time" },
              "contact": { "type": "string", "format": "email" },
              "contact_url": { "type": "string", "format": "uri" }
            }
          },
          "meta": { "$ref": "#/components/schemas/Meta" }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid developer key",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "QuotaExceeded": {
        "description": "Allowance exhausted. The response states when the allowance resets and how to request higher volume.",
        "headers": {
          "X-RateLimit-Limit": { "schema": { "type": "integer" } },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" } },
          "X-RateLimit-Reset": { "schema": { "type": "integer" } }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    }
  }
}
