openapi: 3.1.0
info:
  title: StatuteRates Static JSON and CSV API
  version: "1.1.0"
  description: >
    Free, read-only access to StatuteRates' provenance-tracked statutory, judgment, tax, and
    late-payment interest-rate dataset. Every endpoint is a prebuilt file served from a CDN and
    regenerated by the validated refresh pipeline. Every observation carries effective_date,
    source_url, retrieved_at, confidence, and method. Values currently in force are selected as of
    the dataset snapshot; an officially announced future period remains separately available as
    latest_published, in history, and through /api/v1/upcoming.json. The narrower
    /api/v1/history-coverage.json endpoint lists only historical lookups whose date meaning, legal
    branch, source provenance, coverage boundary, and known gaps have passed a separate release
    review.
  license:
    name: StatuteRates data and API terms
    url: https://statuterates.com/terms/#data-api-license
externalDocs:
  description: StatuteRates API documentation
  url: https://statuterates.com/api/
servers:
  - url: https://statuterates.com
    description: Production CDN
paths:
  /api/v1/index.json:
    get:
      operationId: getServiceIndex
      summary: Service index — links to every endpoint + counts
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  api_version: { type: string }
                  dataset: { type: string }
                  generated_at: { type: string, format: date-time }
                  endpoints: { type: object }
                  counts: { type: object }
  /api/v1/meta.json:
    get:
      operationId: getMeta
      summary: Dataset metadata, freshness, and cited sources
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
  /api/v1/metrics.json:
    get:
      operationId: getMetrics
      summary: List of metric names present in the dataset
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
  /api/v1/entities.json:
    get:
      operationId: getEntities
      summary: Collection index — all entities with current and latest-published values
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
  /api/v1/latest.json:
    get:
      operationId: getLatest
      summary: Flat list of every value currently in force — the one-call integration
      description: No observation whose effective date is after current_as_of appears here.
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
  /api/v1/upcoming.json:
    get:
      operationId: getUpcoming
      summary: Officially announced observations that are not yet in force
      description: Every observation here has an effective date after current_as_of and is never presented as current.
      responses:
        "200":
          description: OK; the observations array can be empty.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
  /api/v1/history-coverage.json:
    get:
      operationId: getHistoricalCoverage
      summary: Released historical lookup series and their verified coverage boundaries
      description: >
        Lists only code-reviewed historical lookup series. Each row explains what the input date
        means, which legal branch the series describes, its first and last verified dates, and any
        interval the lookup must refuse. Historical observations remain in the corresponding
        entity JSON endpoint.
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/Envelope"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/HistoricalCoverageCollection"
  /api/v1/entity/{slug}.json:
    get:
      operationId: getEntity
      summary: One entity — current values, latest-published values, and all recorded observations
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
          description: URL-safe entity slug (see entities.json for the list).
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Envelope"
        "404":
          description: No such entity (the file does not exist on the CDN)
  /api/v1/entity/{slug}.csv:
    get:
      operationId: getEntityCsv
      summary: One entity's recorded observations as CSV (spreadsheet-ready, provenance columns included)
      parameters:
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        "200":
          description: OK
          content:
            text/csv:
              schema: { type: string }
        "404":
          description: No such entity
components:
  schemas:
    Observation:
      type: object
      description: A single value with full provenance.
      required: [metric, unit, effective_date, source_url, retrieved_at, confidence]
      properties:
        metric: { type: string, description: "e.g. the primary metric name" }
        value: { type: [number, "null"], description: "machine-usable numeric value" }
        value_text: { type: [string, "null"], description: "human display / ranges" }
        unit: { type: string }
        effective_date: { type: string, format: date, description: "date the value took effect" }
        source_id: { type: string }
        source_url: { type: string, format: uri, description: "exact page the value came from" }
        retrieved_at: { type: string, format: date-time }
        confidence: { type: string, enum: [high, medium, low] }
        method: { type: [string, "null"] }
        notes: { type: [string, "null"] }
    Entity:
      type: object
      required: [slug, name, entity_type]
      properties:
        slug: { type: string }
        name: { type: string }
        entity_type: { type: string }
        jurisdiction: { type: [string, "null"] }
        region: { type: [string, "null"] }
        locale: { type: [string, "null"] }
        metrics: { type: array, items: { type: string } }
        latest:
          type: object
          description: Backwards-compatible alias for current; never contains a future-effective observation.
          additionalProperties: { $ref: "#/components/schemas/Observation" }
        current:
          type: object
          description: Values in force on current_as_of.
          additionalProperties: { $ref: "#/components/schemas/Observation" }
        latest_published:
          type: object
          description: Newest published values, which can include an officially announced future period.
          additionalProperties: { $ref: "#/components/schemas/Observation" }
        current_as_of: { type: string, format: date }
        history:
          type: object
          additionalProperties:
            type: array
            items: { $ref: "#/components/schemas/Observation" }
    OfficialAuthority:
      type: object
      required: [label, url]
      properties:
        label: { type: string }
        url: { type: string, format: uri }
    CoverageGap:
      type: object
      required: [start, end, reason]
      properties:
        start: { type: string, format: date }
        end: { type: string, format: date }
        reason: { type: string }
    HistoricalCoverageSeries:
      type: object
      required:
        - entity_slug
        - label
        - metric
        - usage
        - calculation_supported
        - input_meaning
        - branch_scope
        - selection_rule
        - coverage_note
        - coverage_start
        - coverage_end
        - history_count
        - gaps
        - source_url
        - official_authorities
        - links
      properties:
        entity_slug: { type: string }
        label: { type: string }
        metric: { type: string, const: annual_rate }
        usage: { type: string, const: reference_only }
        calculation_supported: { type: boolean, const: false }
        input_meaning: { type: string, description: "Legal/date meaning of the requested lookup date." }
        branch_scope: { type: string, description: "Branch represented and material exclusions." }
        selection_rule: { type: string }
        coverage_note: { type: string }
        coverage_start: { type: string, format: date }
        coverage_end: { type: string, format: date, description: "Last date released for lookup; never after current_as_of." }
        history_count: { type: integer, minimum: 2 }
        gaps:
          type: array
          items: { $ref: "#/components/schemas/CoverageGap" }
        source_url: { type: string, format: uri }
        official_authorities:
          type: array
          items: { $ref: "#/components/schemas/OfficialAuthority" }
        links:
          type: object
          required: [page, entity_json, entity_csv, historical_lookup]
          properties:
            page: { type: string }
            entity_json: { type: string }
            entity_csv: { type: string }
            historical_lookup: { type: string }
    HistoricalCoverageCollection:
      type: object
      required: [count, current_as_of, series]
      properties:
        count: { type: integer, minimum: 1 }
        current_as_of: { type: string, format: date }
        series:
          type: array
          items: { $ref: "#/components/schemas/HistoricalCoverageSeries" }
    Envelope:
      type: object
      required: [api_version, generated_at, data]
      properties:
        api_version: { type: string }
        generated_at: { type: string, format: date-time }
        attribution: { type: [string, "null"] }
        license: { type: [string, "null"] }
        data: {}
