openapi: 3.1.0
info:
  title: oaq mirror API
  version: "0.1.0"
  summary: Read-only mirror of the OAQ Data Broker for India.
  description: |
    Open, key-free, read-only access to live air quality data for ~650 stations
    across India. Data is mirrored hourly from [oaq.notf.in](https://oaq.notf.in),
    which aggregates from CPCB, Airnet (CSTEP), and Aurassure.

    This is an unofficial mirror. The upstream handshake and signed-URL flow is
    handled server-side — clients of *this* API never need an API key.

    All endpoints respond with `Cache-Control: public, s-maxage=900, stale-while-revalidate=3600`
    and `Access-Control-Allow-Origin: *`.
  license:
    name: MIT
    identifier: MIT
  contact:
    url: https://github.com/urbanmorph/oaq
servers:
  - url: https://oaq.pages.dev
    description: Production
tags:
  - name: leaderboard
  - name: station
paths:
  /index.json:
    get:
      tags: [leaderboard]
      summary: Full leaderboard snapshot
      description: All stations sorted worst-first by CPCB AQI, with metadata and pollutants.
      responses:
        "200":
          description: Snapshot
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Snapshot"
        "503":
          description: Snapshot not yet generated
  /index.md:
    get:
      tags: [leaderboard]
      summary: Full leaderboard as Markdown
      description: LLM-friendly Markdown rendering of the snapshot — frontmatter, Worst 50, Best 50, by-city tables.
      responses:
        "200":
          description: Markdown
          content:
            text/markdown:
              schema: { type: string }
  /s/{provider}/{id}.json:
    get:
      tags: [station]
      summary: Single station as JSON
      parameters:
        - { name: provider, in: path, required: true, schema: { $ref: "#/components/schemas/ProviderId" } }
        - { name: id, in: path, required: true, schema: { type: string }, description: Upstream station id }
      responses:
        "200":
          description: Station
          content:
            application/json:
              schema:
                type: object
                required: [generated_at, station]
                properties:
                  generated_at: { type: string, format: date-time }
                  station: { $ref: "#/components/schemas/Station" }
        "404": { description: Station not found }
  /s/{provider}/{id}.md:
    get:
      tags: [station]
      summary: Single station as Markdown
      parameters:
        - { name: provider, in: path, required: true, schema: { $ref: "#/components/schemas/ProviderId" } }
        - { name: id, in: path, required: true, schema: { type: string } }
      responses:
        "200":
          description: Markdown
          content:
            text/markdown:
              schema: { type: string }
components:
  schemas:
    ProviderId:
      type: string
      enum: [cpcb, airnet, aurassure]
    Band:
      type: string
      enum: [good, satisfactory, moderate, poor, vpoor, severe, unknown]
    Station:
      type: object
      required: [id, raw_id, provider, name, city, state, pollutants, aqi, band]
      properties:
        id: { type: string, example: "cpcb-1420" }
        raw_id: { type: string, example: "1420" }
        provider: { $ref: "#/components/schemas/ProviderId" }
        name: { type: string, example: "Anand Vihar" }
        city: { type: string, example: "Delhi" }
        state: { type: string }
        lat: { type: [number, "null"] }
        lon: { type: [number, "null"] }
        aqi: { type: [integer, "null"], minimum: 0, maximum: 500 }
        band: { $ref: "#/components/schemas/Band" }
        ts: { type: [string, "null"], format: date-time }
        pollutants:
          type: object
          properties:
            pm25: { type: number, description: "µg/m³" }
            pm10: { type: number, description: "µg/m³" }
            no2:  { type: number, description: "µg/m³" }
            so2:  { type: number, description: "µg/m³" }
            co:   { type: number, description: "mg/m³" }
            o3:   { type: number, description: "µg/m³" }
            nh3:  { type: number, description: "µg/m³" }
    Snapshot:
      type: object
      required: [generated_at, station_count, providers, stations]
      properties:
        generated_at: { type: string, format: date-time }
        station_count: { type: integer }
        providers:
          type: array
          items: { $ref: "#/components/schemas/ProviderId" }
        stations:
          type: array
          items: { $ref: "#/components/schemas/Station" }
