openapi: 3.1.0
info:
  title: SOSRoute API
  description: |
    SOSRoute is a developer-first public safety data API by Sandbox Synergy.

    Aggregate, normalize, and query real-time hazard alerts, incident reports, geofence 
    safety zones, location intelligence, emergency contacts, and webhook notifications 
    through a single, clean REST interface.

    ## Data Sources
    SOSRoute ingests and normalizes data from 6 authoritative government sources:
    - **FEMA IPAWS** — Emergency alerts (AMBER, weather, civil emergencies)
    - **NOAA Weather** — Severe weather alerts and forecasts
    - **USGS Earthquake** — Earthquake events, magnitude, and location
    - **FBI UCR** — Crime statistics by region
    - **NIFC Wildfire** — Active wildfires, perimeters, and containment status
    - **EPA AirNow** — Air quality index (AQI) and pollutant levels

    ## Authentication
    All requests require an API key passed in the `X-API-Key` header.
    Get your free key at [dashboard.sosroute.dev](https://dashboard.sosroute.dev).

    ## Rate Limits
    | Plan | Requests/Minute | Requests/Day |
    |------|----------------|--------------|
    | Free | 100 | 10,000 |
    | Starter ($49/mo) | 1,000 | 100,000 |
    | Pro ($199/mo) | 10,000 | 1,000,000 |
    | Enterprise | Custom | Custom |

    Rate limit status is returned in response headers:
    `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`

    ## Environments
    - **Production:** `https://api.sosroute.dev/v1`
    - **Sandbox:** `https://sandbox.sosroute.dev/v1` (synthetic data, no rate limits)
  version: 1.0.0
  contact:
    name: SOSRoute Developer Support
    url: https://docs.sosroute.dev/support
    email: developers@sosroute.dev
  license:
    name: Proprietary
    url: https://sosroute.dev/license
  termsOfService: https://sosroute.dev/terms

servers:
  - url: https://api.sosroute.dev/v1
    description: Production
  - url: https://sandbox.sosroute.dev/v1
    description: Sandbox (synthetic data)

security:
  - ApiKeyAuth: []

tags:
  - name: Hazard Alerts
    description: Query real-time hazard alerts aggregated from FEMA, NOAA, USGS, NIFC, and EPA
  - name: Incident Reporting
    description: Create and manage incident reports within your organization
  - name: Geofence Safety Zones
    description: Define geographic boundaries and check if coordinates fall within them
  - name: Location Intelligence
    description: Get composite risk scores and nearby hazard analysis for any location
  - name: Emergency Contacts
    description: Find nearest emergency services (fire, police, EMS, hospital)
  - name: Webhooks
    description: Subscribe to real-time event notifications via HTTPS webhooks

paths:
  # ─── HAZARD ALERTS ──────────────────────────────────────────────────
  /alerts:
    get:
      tags:
        - Hazard Alerts
      summary: List active alerts
      description: |
        Returns a paginated list of active hazard alerts within a geographic radius.
        Results are sorted by severity (critical first), then by recency.

        Alerts are aggregated from FEMA IPAWS, NOAA Weather, USGS Earthquake, 
        NIFC Wildfire, and EPA AirNow.
      operationId: listAlerts
      parameters:
        - name: lat
          in: query
          required: true
          description: Latitude of the search center point
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7128
        - name: lng
          in: query
          required: true
          description: Longitude of the search center point
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -74.0060
        - name: radius
          in: query
          required: false
          description: Search radius in kilometers (default 50, max 500)
          schema:
            type: number
            format: double
            minimum: 1
            maximum: 500
            default: 50
          example: 25
        - name: category
          in: query
          required: false
          description: Filter by alert category
          schema:
            type: string
            enum:
              - weather
              - earthquake
              - wildfire
              - air_quality
              - flood
              - tsunami
              - civil
              - amber
          example: weather
        - name: severity
          in: query
          required: false
          description: Minimum severity level to include
          schema:
            type: string
            enum:
              - info
              - minor
              - moderate
              - severe
              - extreme
          example: moderate
        - name: limit
          in: query
          required: false
          description: Number of results per page (default 20, max 100)
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          example: 10
        - name: cursor
          in: query
          required: false
          description: Pagination cursor from previous response
          schema:
            type: string
          example: eyJpZCI6ImFsZXJ0XzEyMzQ1In0=
      responses:
        '200':
          description: List of active alerts
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Rate limit ceiling for this key
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Remaining requests in current window
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when rate limit resets
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedAlertResponse'
              example:
                data:
                  - id: "alert_9f8e7d6c"
                    source: "noaa"
                    source_id: "urn:oid:2.49.0.1.840.0.2024.7.14.12.45.0"
                    category: "weather"
                    severity: "severe"
                    title: "Severe Thunderstorm Warning"
                    description: "The National Weather Service has issued a severe thunderstorm warning for Manhattan, NY. Damaging winds up to 70 mph and quarter-size hail expected. Seek shelter immediately."
                    location:
                      type: "Point"
                      coordinates: [-73.9857, 40.7484]
                    radius_km: 15.0
                    effective_at: "2026-07-14T16:00:00Z"
                    expires_at: "2026-07-14T18:00:00Z"
                    source_url: "https://alerts.weather.gov/cap/wwacapget.php?x=NY1264..."
                    data_freshness: "live"
                  - id: "alert_a1b2c3d4"
                    source: "epa"
                    source_id: "AQI-NY-36061-20260714"
                    category: "air_quality"
                    severity: "moderate"
                    title: "Air Quality Advisory — Moderate"
                    description: "Air Quality Index is 112 (Unhealthy for Sensitive Groups). PM2.5 levels elevated due to wildfire smoke transport. Sensitive individuals should limit prolonged outdoor exertion."
                    location:
                      type: "Point"
                      coordinates: [-73.9712, 40.7831]
                    radius_km: 30.0
                    effective_at: "2026-07-14T12:00:00Z"
                    expires_at: "2026-07-14T23:59:00Z"
                    source_url: "https://www.airnowapi.org/aq/observation/zipCode/current/?zipCode=10001"
                    data_freshness: "live"
                pagination:
                  has_more: true
                  next_cursor: "eyJpZCI6ImFsZXJ0X2ExYjJjM2Q0In0="
                  total_count: 7
                meta:
                  sources_queried:
                    - noaa
                    - fema
                    - epa
                    - usgs
                  request_id: "req_f1e2d3c4"
                  latency_ms: 47
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /alerts/{id}:
    get:
      tags:
        - Hazard Alerts
      summary: Get single alert
      description: Retrieve the full details of a specific alert by its SOSRoute ID.
      operationId: getAlert
      parameters:
        - name: id
          in: path
          required: true
          description: SOSRoute alert ID
          schema:
            type: string
          example: alert_9f8e7d6c
      responses:
        '200':
          description: Alert details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Alert'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "alert_9f8e7d6c"
                  source: "noaa"
                  source_id: "urn:oid:2.49.0.1.840.0.2024.7.14.12.45.0"
                  category: "weather"
                  severity: "severe"
                  title: "Severe Thunderstorm Warning"
                  description: "The National Weather Service has issued a severe thunderstorm warning for Manhattan, NY. Damaging winds up to 70 mph and quarter-size hail expected. Seek shelter immediately."
                  location:
                    type: "Point"
                    coordinates: [-73.9857, 40.7484]
                  radius_km: 15.0
                  effective_at: "2026-07-14T16:00:00Z"
                  expires_at: "2026-07-14T18:00:00Z"
                  source_url: "https://alerts.weather.gov/cap/wwacapget.php?x=NY1264..."
                  raw_data:
                    nws_headline: "SEVERE THUNDERSTORM WARNING"
                    nws_event: "Severe Thunderstorm Warning"
                    wind_mph: 70
                    hail_inches: 1.0
                  data_freshness: "live"
                meta:
                  request_id: "req_g5h6i7j8"
                  latency_ms: 12
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /alerts/subscribe:
    post:
      tags:
        - Hazard Alerts
      summary: Subscribe to alert category
      description: |
        Create a subscription to receive notifications when new alerts matching 
        your criteria are published. Notifications are delivered via configured 
        webhooks (see Webhooks endpoints).
      operationId: subscribeToAlerts
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - category
                - location
                - radius_km
              properties:
                category:
                  type: string
                  enum:
                    - weather
                    - earthquake
                    - wildfire
                    - air_quality
                    - flood
                    - tsunami
                    - civil
                    - amber
                    - all
                  description: Alert category to subscribe to. Use "all" for all categories.
                severity_min:
                  type: string
                  enum:
                    - info
                    - minor
                    - moderate
                    - severe
                    - extreme
                  default: minor
                  description: Minimum severity to trigger notification
                location:
                  $ref: '#/components/schemas/GeoPoint'
                radius_km:
                  type: number
                  format: double
                  minimum: 1
                  maximum: 500
                  description: Radius in kilometers around the location
            example:
              category: "weather"
              severity_min: "moderate"
              location:
                lat: 40.7128
                lng: -74.0060
              radius_km: 50
      responses:
        '201':
          description: Subscription created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/AlertSubscription'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "sub_x1y2z3"
                  category: "weather"
                  severity_min: "moderate"
                  location:
                    lat: 40.7128
                    lng: -74.0060
                  radius_km: 50
                  is_active: true
                  created_at: "2026-07-14T16:10:39Z"
                meta:
                  request_id: "req_k9l0m1n2"
                  latency_ms: 34
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  # ─── INCIDENT REPORTING ─────────────────────────────────────────────
  /incidents:
    post:
      tags:
        - Incident Reporting
      summary: Create incident report
      description: |
        Submit a new incident report. Incidents are organization-scoped and 
        can be used to track safety events reported by your users or systems.
      operationId: createIncident
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - category
                - location
              properties:
                title:
                  type: string
                  maxLength: 200
                  description: Short title describing the incident
                description:
                  type: string
                  maxLength: 5000
                  description: Detailed description of the incident
                category:
                  type: string
                  enum:
                    - hazard
                    - accident
                    - weather
                    - infrastructure
                    - environmental
                    - security
                    - medical
                    - other
                  description: Incident category
                severity:
                  type: string
                  enum:
                    - low
                    - medium
                    - high
                    - critical
                  default: medium
                  description: Severity of the incident
                location:
                  $ref: '#/components/schemas/GeoPoint'
                metadata:
                  type: object
                  description: Arbitrary key-value metadata for your application
                  additionalProperties: true
            example:
              title: "Downed power line on 5th Avenue"
              description: "Large tree fell during storm, bringing down power lines across 5th Avenue between 42nd and 43rd Street. Area is blocked. Sparking observed."
              category: "infrastructure"
              severity: "high"
              location:
                lat: 40.7549
                lng: -73.9840
              metadata:
                reporter_id: "user_abc123"
                photos: 2
                blocking_traffic: true
      responses:
        '201':
          description: Incident created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Incident'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "inc_m4n5o6p7"
                  org_id: "org_xyz789"
                  status: "open"
                  title: "Downed power line on 5th Avenue"
                  description: "Large tree fell during storm, bringing down power lines across 5th Avenue between 42nd and 43rd Street. Area is blocked. Sparking observed."
                  category: "infrastructure"
                  severity: "high"
                  location:
                    type: "Point"
                    coordinates: [-73.9840, 40.7549]
                  metadata:
                    reporter_id: "user_abc123"
                    photos: 2
                    blocking_traffic: true
                  reported_at: "2026-07-14T16:15:00Z"
                  resolved_at: null
                  created_at: "2026-07-14T16:15:00Z"
                  updated_at: "2026-07-14T16:15:00Z"
                meta:
                  request_id: "req_q3r4s5t6"
                  latency_ms: 56
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    get:
      tags:
        - Incident Reporting
      summary: List incidents
      description: |
        Returns a paginated list of incidents for your organization. 
        Optionally filter by location, status, or time range.
      operationId: listIncidents
      parameters:
        - name: lat
          in: query
          required: false
          description: Latitude for geographic filtering
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7128
        - name: lng
          in: query
          required: false
          description: Longitude for geographic filtering
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -74.0060
        - name: radius
          in: query
          required: false
          description: Search radius in km (requires lat and lng)
          schema:
            type: number
            format: double
            minimum: 1
            maximum: 500
            default: 50
          example: 10
        - name: status
          in: query
          required: false
          description: Filter by incident status
          schema:
            type: string
            enum:
              - open
              - investigating
              - resolved
              - closed
          example: open
        - name: since
          in: query
          required: false
          description: Only return incidents reported after this ISO 8601 timestamp
          schema:
            type: string
            format: date-time
          example: "2026-07-14T00:00:00Z"
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: List of incidents
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedIncidentResponse'
              example:
                data:
                  - id: "inc_m4n5o6p7"
                    org_id: "org_xyz789"
                    status: "open"
                    title: "Downed power line on 5th Avenue"
                    category: "infrastructure"
                    severity: "high"
                    location:
                      type: "Point"
                      coordinates: [-73.9840, 40.7549]
                    reported_at: "2026-07-14T16:15:00Z"
                    resolved_at: null
                    created_at: "2026-07-14T16:15:00Z"
                    updated_at: "2026-07-14T16:15:00Z"
                pagination:
                  has_more: false
                  next_cursor: null
                  total_count: 1
                meta:
                  request_id: "req_u7v8w9x0"
                  latency_ms: 38
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /incidents/{id}:
    get:
      tags:
        - Incident Reporting
      summary: Get incident
      description: Retrieve the full details of a specific incident by ID.
      operationId: getIncident
      parameters:
        - name: id
          in: path
          required: true
          description: Incident ID
          schema:
            type: string
          example: inc_m4n5o6p7
      responses:
        '200':
          description: Incident details
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Incident'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /incidents/{id}/status:
    patch:
      tags:
        - Incident Reporting
      summary: Update incident status
      description: Update the status of an incident (e.g., move from "open" to "investigating" or "resolved").
      operationId: updateIncidentStatus
      parameters:
        - name: id
          in: path
          required: true
          description: Incident ID
          schema:
            type: string
          example: inc_m4n5o6p7
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    - open
                    - investigating
                    - resolved
                    - closed
                  description: New status for the incident
                resolution_notes:
                  type: string
                  maxLength: 2000
                  description: Notes about the resolution (recommended when setting status to "resolved")
            example:
              status: "resolved"
              resolution_notes: "Con Edison crew removed the downed line and restored power at 18:30. Road reopened to traffic."
      responses:
        '200':
          description: Incident status updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Incident'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "inc_m4n5o6p7"
                  org_id: "org_xyz789"
                  status: "resolved"
                  title: "Downed power line on 5th Avenue"
                  category: "infrastructure"
                  severity: "high"
                  location:
                    type: "Point"
                    coordinates: [-73.9840, 40.7549]
                  metadata:
                    reporter_id: "user_abc123"
                    resolution_notes: "Con Edison crew removed the downed line and restored power at 18:30. Road reopened to traffic."
                  reported_at: "2026-07-14T16:15:00Z"
                  resolved_at: "2026-07-14T18:35:00Z"
                  created_at: "2026-07-14T16:15:00Z"
                  updated_at: "2026-07-14T18:35:00Z"
                meta:
                  request_id: "req_a1b2c3d4"
                  latency_ms: 29
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  # ─── GEOFENCE SAFETY ZONES ─────────────────────────────────────────
  /geofences:
    post:
      tags:
        - Geofence Safety Zones
      summary: Create geofence
      description: |
        Create a geofence (safety zone) defined by a center point and radius, 
        or by a GeoJSON polygon. When alerts occur inside the geofence, 
        configured webhooks will fire.
      operationId: createGeofence
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - center
                - radius_km
              properties:
                name:
                  type: string
                  maxLength: 100
                  description: Human-readable name for this geofence
                center:
                  $ref: '#/components/schemas/GeoPoint'
                radius_km:
                  type: number
                  format: double
                  minimum: 0.1
                  maximum: 500
                  description: Radius in kilometers
                alert_categories:
                  type: array
                  items:
                    type: string
                    enum:
                      - weather
                      - earthquake
                      - wildfire
                      - air_quality
                      - flood
                      - tsunami
                      - civil
                      - amber
                  description: Alert categories to monitor within this geofence (default all)
            example:
              name: "NYC Office Campus"
              center:
                lat: 40.7580
                lng: -73.9855
              radius_km: 5
              alert_categories:
                - weather
                - earthquake
                - air_quality
      responses:
        '201':
          description: Geofence created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Geofence'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "geo_e5f6g7h8"
                  org_id: "org_xyz789"
                  name: "NYC Office Campus"
                  center:
                    type: "Point"
                    coordinates: [-73.9855, 40.7580]
                  radius_km: 5
                  alert_categories:
                    - weather
                    - earthquake
                    - air_quality
                  is_active: true
                  created_at: "2026-07-14T16:20:00Z"
                  updated_at: "2026-07-14T16:20:00Z"
                meta:
                  request_id: "req_b2c3d4e5"
                  latency_ms: 41
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    get:
      tags:
        - Geofence Safety Zones
      summary: List geofences
      description: Returns all geofences for your organization.
      operationId: listGeofences
      parameters:
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: cursor
          in: query
          required: false
          schema:
            type: string
      responses:
        '200':
          description: List of geofences
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedGeofenceResponse'
              example:
                data:
                  - id: "geo_e5f6g7h8"
                    org_id: "org_xyz789"
                    name: "NYC Office Campus"
                    center:
                      type: "Point"
                      coordinates: [-73.9855, 40.7580]
                    radius_km: 5
                    alert_categories:
                      - weather
                      - earthquake
                      - air_quality
                    is_active: true
                    created_at: "2026-07-14T16:20:00Z"
                    updated_at: "2026-07-14T16:20:00Z"
                  - id: "geo_i9j0k1l2"
                    org_id: "org_xyz789"
                    name: "Jersey City Warehouse"
                    center:
                      type: "Point"
                      coordinates: [-74.0431, 40.7178]
                    radius_km: 2
                    alert_categories:
                      - weather
                      - flood
                    is_active: true
                    created_at: "2026-07-10T09:00:00Z"
                    updated_at: "2026-07-10T09:00:00Z"
                pagination:
                  has_more: false
                  next_cursor: null
                  total_count: 2
                meta:
                  request_id: "req_f6g7h8i9"
                  latency_ms: 22
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /geofences/check:
    get:
      tags:
        - Geofence Safety Zones
      summary: Check point against geofences
      description: |
        Check if a given point (lat/lng) falls inside any of your organization's 
        active geofences. Returns all matching geofences and any active alerts 
        within those geofences.
      operationId: checkGeofence
      parameters:
        - name: lat
          in: query
          required: true
          description: Latitude to check
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7580
        - name: lng
          in: query
          required: true
          description: Longitude to check
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -73.9855
      responses:
        '200':
          description: Geofence check result
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      inside_geofences:
                        type: array
                        items:
                          $ref: '#/components/schemas/GeofenceCheckResult'
                      point:
                        $ref: '#/components/schemas/GeoPoint'
                      total_matching:
                        type: integer
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  inside_geofences:
                    - geofence:
                        id: "geo_e5f6g7h8"
                        name: "NYC Office Campus"
                      distance_from_center_km: 0.3
                      active_alerts_inside: 1
                      alerts:
                        - id: "alert_9f8e7d6c"
                          category: "weather"
                          severity: "severe"
                          title: "Severe Thunderstorm Warning"
                  point:
                    lat: 40.7580
                    lng: -73.9855
                  total_matching: 1
                meta:
                  request_id: "req_j0k1l2m3"
                  latency_ms: 55
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /geofences/{id}:
    delete:
      tags:
        - Geofence Safety Zones
      summary: Delete geofence
      description: Permanently delete a geofence. This also removes any alert subscriptions tied to this geofence.
      operationId: deleteGeofence
      parameters:
        - name: id
          in: path
          required: true
          description: Geofence ID
          schema:
            type: string
          example: geo_e5f6g7h8
      responses:
        '204':
          description: Geofence deleted successfully
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  # ─── LOCATION INTELLIGENCE ─────────────────────────────────────────
  /location/risk-score:
    get:
      tags:
        - Location Intelligence
      summary: Get composite risk score
      description: |
        Returns a composite risk score (0-100) for a given location, aggregating 
        data from all available sources. The score considers active alerts, 
        historical incident density, crime statistics, environmental factors, 
        and seismic activity.
      operationId: getRiskScore
      parameters:
        - name: lat
          in: query
          required: true
          description: Latitude
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7128
        - name: lng
          in: query
          required: true
          description: Longitude
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -74.0060
      responses:
        '200':
          description: Composite risk score
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/RiskScore'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  overall_score: 42
                  risk_level: "moderate"
                  location:
                    lat: 40.7128
                    lng: -74.0060
                    city: "New York"
                    state: "NY"
                    country: "US"
                  breakdown:
                    weather:
                      score: 65
                      level: "elevated"
                      active_alerts: 2
                      description: "Severe thunderstorm warning active"
                    seismic:
                      score: 8
                      level: "low"
                      recent_events: 0
                      description: "No significant seismic activity"
                    crime:
                      score: 55
                      level: "moderate"
                      description: "Property crime rate above national average"
                    fire:
                      score: 5
                      level: "low"
                      active_wildfires_nearby: 0
                      description: "No active wildfires within 200km"
                    air_quality:
                      score: 62
                      level: "moderate"
                      aqi: 112
                      description: "Unhealthy for sensitive groups (PM2.5 elevated)"
                    flood:
                      score: 30
                      level: "low"
                      description: "Minor flood risk in low-lying areas"
                  computed_at: "2026-07-14T16:25:00Z"
                  valid_for_seconds: 300
                meta:
                  request_id: "req_n4o5p6q7"
                  latency_ms: 128
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /location/nearby-hazards:
    get:
      tags:
        - Location Intelligence
      summary: Get nearby active hazards
      description: |
        Returns all active hazards near a given location, sorted by proximity. 
        This is a convenience endpoint that combines alerts, environmental data, 
        and real-time hazard information.
      operationId: getNearbyHazards
      parameters:
        - name: lat
          in: query
          required: true
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7128
        - name: lng
          in: query
          required: true
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -74.0060
        - name: radius
          in: query
          required: false
          schema:
            type: number
            format: double
            minimum: 1
            maximum: 500
            default: 50
          example: 25
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
      responses:
        '200':
          description: Nearby hazards
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/NearbyHazard'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  - type: "weather_alert"
                    id: "alert_9f8e7d6c"
                    title: "Severe Thunderstorm Warning"
                    severity: "severe"
                    distance_km: 3.2
                    direction: "NE"
                    location:
                      type: "Point"
                      coordinates: [-73.9857, 40.7484]
                    source: "noaa"
                  - type: "air_quality"
                    id: "alert_a1b2c3d4"
                    title: "Air Quality Advisory — Moderate (AQI 112)"
                    severity: "moderate"
                    distance_km: 8.1
                    direction: "N"
                    location:
                      type: "Point"
                      coordinates: [-73.9712, 40.7831]
                    source: "epa"
                meta:
                  request_id: "req_r8s9t0u1"
                  latency_ms: 67
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  # ─── EMERGENCY CONTACTS ────────────────────────────────────────────
  /contacts/nearest:
    get:
      tags:
        - Emergency Contacts
      summary: Get nearest emergency services
      description: |
        Returns the nearest emergency services (fire stations, police stations, 
        hospitals, EMS) to a given location. Results include distance, contact 
        information, and service type.
      operationId: getNearestContacts
      parameters:
        - name: lat
          in: query
          required: true
          description: Latitude
          schema:
            type: number
            format: double
            minimum: -90
            maximum: 90
          example: 40.7128
        - name: lng
          in: query
          required: true
          description: Longitude
          schema:
            type: number
            format: double
            minimum: -180
            maximum: 180
          example: -74.0060
        - name: type
          in: query
          required: false
          description: Filter by service type (default returns all types)
          schema:
            type: string
            enum:
              - fire
              - police
              - hospital
              - ems
          example: hospital
        - name: limit
          in: query
          required: false
          description: Number of results (default 5, max 20)
          schema:
            type: integer
            minimum: 1
            maximum: 20
            default: 5
          example: 3
      responses:
        '200':
          description: Nearest emergency contacts
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/EmergencyContact'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  - id: "contact_h1i2j3"
                    type: "hospital"
                    name: "NYU Langone Health — Tisch Hospital"
                    address: "550 1st Avenue, New York, NY 10016"
                    phone: "+1-212-263-7300"
                    distance_km: 2.1
                    direction: "NE"
                    location:
                      type: "Point"
                      coordinates: [-73.9741, 40.7421]
                    services:
                      - "Emergency Room"
                      - "Trauma Center (Level I)"
                      - "Burn Center"
                    hours: "24/7"
                  - id: "contact_k4l5m6"
                    type: "hospital"
                    name: "NewYork-Presbyterian Lower Manhattan Hospital"
                    address: "170 William Street, New York, NY 10038"
                    phone: "+1-212-312-5000"
                    distance_km: 0.8
                    direction: "SE"
                    location:
                      type: "Point"
                      coordinates: [-74.0061, 40.7098]
                    services:
                      - "Emergency Room"
                      - "Trauma Center (Level II)"
                    hours: "24/7"
                  - id: "contact_n7o8p9"
                    type: "hospital"
                    name: "Mount Sinai Beth Israel"
                    address: "281 1st Avenue, New York, NY 10003"
                    phone: "+1-212-420-2000"
                    distance_km: 3.4
                    direction: "N"
                    location:
                      type: "Point"
                      coordinates: [-73.9819, 40.7312]
                    services:
                      - "Emergency Room"
                    hours: "24/7"
                meta:
                  request_id: "req_v2w3x4y5"
                  latency_ms: 89
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  # ─── WEBHOOKS ───────────────────────────────────────────────────────
  /webhooks:
    post:
      tags:
        - Webhooks
      summary: Create webhook subscription
      description: |
        Register a webhook URL to receive real-time notifications when events 
        occur. Each webhook delivery includes an HMAC-SHA256 signature in the 
        `X-SOSRoute-Signature` header for verification.
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
                - event_types
              properties:
                url:
                  type: string
                  format: uri
                  description: HTTPS URL to receive webhook POST requests
                event_types:
                  type: array
                  items:
                    type: string
                    enum:
                      - alert.created
                      - alert.updated
                      - alert.expired
                      - incident.created
                      - incident.status_changed
                      - geofence.alert_entered
                      - geofence.alert_exited
                  description: Event types to subscribe to
                description:
                  type: string
                  maxLength: 200
                  description: Optional description for this webhook
            example:
              url: "https://myapp.example.com/webhooks/sosroute"
              event_types:
                - "alert.created"
                - "geofence.alert_entered"
              description: "Production alert notifications"
      responses:
        '201':
          description: Webhook created
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/Webhook'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  id: "wh_z1a2b3c4"
                  url: "https://myapp.example.com/webhooks/sosroute"
                  event_types:
                    - "alert.created"
                    - "geofence.alert_entered"
                  description: "Production alert notifications"
                  secret: "whsec_d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9"
                  is_active: true
                  failure_count: 0
                  last_triggered_at: null
                  created_at: "2026-07-14T16:30:00Z"
                meta:
                  request_id: "req_a5b6c7d8"
                  latency_ms: 31
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

    get:
      tags:
        - Webhooks
      summary: List webhooks
      description: Returns all webhook subscriptions for your organization.
      operationId: listWebhooks
      responses:
        '200':
          description: List of webhooks
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Webhook'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
              example:
                data:
                  - id: "wh_z1a2b3c4"
                    url: "https://myapp.example.com/webhooks/sosroute"
                    event_types:
                      - "alert.created"
                      - "geofence.alert_entered"
                    description: "Production alert notifications"
                    is_active: true
                    failure_count: 0
                    last_triggered_at: "2026-07-14T16:45:00Z"
                    created_at: "2026-07-14T16:30:00Z"
                meta:
                  request_id: "req_e9f0g1h2"
                  latency_ms: 15
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /webhooks/{id}:
    delete:
      tags:
        - Webhooks
      summary: Delete webhook
      description: Permanently delete a webhook subscription. No further events will be delivered to this URL.
      operationId: deleteWebhook
      parameters:
        - name: id
          in: path
          required: true
          description: Webhook ID
          schema:
            type: string
          example: wh_z1a2b3c4
      responses:
        '204':
          description: Webhook deleted successfully
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

# ═══════════════════════════════════════════════════════════════════════
# COMPONENTS
# ═══════════════════════════════════════════════════════════════════════
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for authentication. Obtain from [SOSRoute Dashboard](https://dashboard.sosroute.dev).
        Keys are prefixed with `sos_live_` (production) or `sos_test_` (sandbox).

  schemas:
    # ─── Core Resources ──────────────────────────────────────────────
    Alert:
      type: object
      properties:
        id:
          type: string
          description: Unique SOSRoute alert ID
          example: "alert_9f8e7d6c"
        source:
          type: string
          enum: [fema, noaa, usgs, nifc, epa]
          description: Originating data source
          example: "noaa"
        source_id:
          type: string
          description: Original ID from the source system
          example: "urn:oid:2.49.0.1.840.0.2024.7.14.12.45.0"
        category:
          type: string
          enum: [weather, earthquake, wildfire, air_quality, flood, tsunami, civil, amber]
          description: Normalized alert category
          example: "weather"
        severity:
          type: string
          enum: [info, minor, moderate, severe, extreme]
          description: Normalized severity level
          example: "severe"
        title:
          type: string
          description: Human-readable alert title
          example: "Severe Thunderstorm Warning"
        description:
          type: string
          description: Detailed alert description
          example: "The National Weather Service has issued a severe thunderstorm warning..."
        location:
          type: object
          description: GeoJSON Point
          properties:
            type:
              type: string
              example: "Point"
            coordinates:
              type: array
              items:
                type: number
              description: "[longitude, latitude]"
              example: [-73.9857, 40.7484]
        radius_km:
          type: number
          format: double
          description: Affected radius in kilometers
          example: 15.0
        effective_at:
          type: string
          format: date-time
          description: When the alert becomes effective
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the alert expires (null if indefinite)
        source_url:
          type: string
          format: uri
          description: Link to the original source alert
        raw_data:
          type: object
          description: Original data from the source (varies by source)
          additionalProperties: true
        data_freshness:
          type: string
          enum: [live, cached, stale]
          description: Indicates if data is live, served from cache, or stale

    Incident:
      type: object
      properties:
        id:
          type: string
          example: "inc_m4n5o6p7"
        org_id:
          type: string
          example: "org_xyz789"
        status:
          type: string
          enum: [open, investigating, resolved, closed]
          example: "open"
        title:
          type: string
          example: "Downed power line on 5th Avenue"
        description:
          type: string
          nullable: true
        category:
          type: string
          enum: [hazard, accident, weather, infrastructure, environmental, security, medical, other]
          example: "infrastructure"
        severity:
          type: string
          enum: [low, medium, high, critical]
          example: "high"
        location:
          type: object
          properties:
            type:
              type: string
              example: "Point"
            coordinates:
              type: array
              items:
                type: number
              example: [-73.9840, 40.7549]
        metadata:
          type: object
          additionalProperties: true
          nullable: true
        reported_at:
          type: string
          format: date-time
        resolved_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    Geofence:
      type: object
      properties:
        id:
          type: string
          example: "geo_e5f6g7h8"
        org_id:
          type: string
          example: "org_xyz789"
        name:
          type: string
          example: "NYC Office Campus"
        center:
          type: object
          properties:
            type:
              type: string
              example: "Point"
            coordinates:
              type: array
              items:
                type: number
              example: [-73.9855, 40.7580]
        radius_km:
          type: number
          format: double
          example: 5
        alert_categories:
          type: array
          items:
            type: string
          example: ["weather", "earthquake", "air_quality"]
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    RiskScore:
      type: object
      properties:
        overall_score:
          type: integer
          minimum: 0
          maximum: 100
          description: "Composite risk score (0 = safest, 100 = highest risk)"
          example: 42
        risk_level:
          type: string
          enum: [low, moderate, elevated, high, extreme]
          example: "moderate"
        location:
          type: object
          properties:
            lat:
              type: number
              example: 40.7128
            lng:
              type: number
              example: -74.0060
            city:
              type: string
              example: "New York"
            state:
              type: string
              example: "NY"
            country:
              type: string
              example: "US"
        breakdown:
          type: object
          properties:
            weather:
              $ref: '#/components/schemas/RiskFactor'
            seismic:
              $ref: '#/components/schemas/RiskFactor'
            crime:
              $ref: '#/components/schemas/RiskFactor'
            fire:
              $ref: '#/components/schemas/RiskFactor'
            air_quality:
              $ref: '#/components/schemas/RiskFactor'
            flood:
              $ref: '#/components/schemas/RiskFactor'
        computed_at:
          type: string
          format: date-time
        valid_for_seconds:
          type: integer
          description: How long this score is considered valid before re-querying
          example: 300

    RiskFactor:
      type: object
      properties:
        score:
          type: integer
          minimum: 0
          maximum: 100
          example: 65
        level:
          type: string
          enum: [low, moderate, elevated, high, extreme]
          example: "elevated"
        description:
          type: string
          example: "Severe thunderstorm warning active"

    EmergencyContact:
      type: object
      properties:
        id:
          type: string
          example: "contact_h1i2j3"
        type:
          type: string
          enum: [fire, police, hospital, ems]
          example: "hospital"
        name:
          type: string
          example: "NYU Langone Health — Tisch Hospital"
        address:
          type: string
          example: "550 1st Avenue, New York, NY 10016"
        phone:
          type: string
          example: "+1-212-263-7300"
        distance_km:
          type: number
          format: double
          example: 2.1
        direction:
          type: string
          description: Cardinal or intercardinal direction from the query point
          example: "NE"
        location:
          type: object
          properties:
            type:
              type: string
              example: "Point"
            coordinates:
              type: array
              items:
                type: number
              example: [-73.9741, 40.7421]
        services:
          type: array
          items:
            type: string
          description: List of services offered
          example: ["Emergency Room", "Trauma Center (Level I)", "Burn Center"]
        hours:
          type: string
          example: "24/7"

    Webhook:
      type: object
      properties:
        id:
          type: string
          example: "wh_z1a2b3c4"
        url:
          type: string
          format: uri
          example: "https://myapp.example.com/webhooks/sosroute"
        event_types:
          type: array
          items:
            type: string
          example: ["alert.created", "geofence.alert_entered"]
        description:
          type: string
          nullable: true
          example: "Production alert notifications"
        secret:
          type: string
          description: "Webhook signing secret (only returned on creation)"
          example: "whsec_d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9"
        is_active:
          type: boolean
          example: true
        failure_count:
          type: integer
          description: Consecutive delivery failures (webhook disabled at 10)
          example: 0
        last_triggered_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time

    AlertSubscription:
      type: object
      properties:
        id:
          type: string
          example: "sub_x1y2z3"
        category:
          type: string
          example: "weather"
        severity_min:
          type: string
          example: "moderate"
        location:
          $ref: '#/components/schemas/GeoPoint'
        radius_km:
          type: number
          format: double
          example: 50
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time

    # ─── Supporting Schemas ───────────────────────────────────────────
    GeoPoint:
      type: object
      required:
        - lat
        - lng
      properties:
        lat:
          type: number
          format: double
          minimum: -90
          maximum: 90
          description: Latitude
          example: 40.7128
        lng:
          type: number
          format: double
          minimum: -180
          maximum: 180
          description: Longitude
          example: -74.0060

    NearbyHazard:
      type: object
      properties:
        type:
          type: string
          description: Hazard type identifier
          example: "weather_alert"
        id:
          type: string
          example: "alert_9f8e7d6c"
        title:
          type: string
          example: "Severe Thunderstorm Warning"
        severity:
          type: string
          example: "severe"
        distance_km:
          type: number
          format: double
          example: 3.2
        direction:
          type: string
          example: "NE"
        location:
          type: object
          properties:
            type:
              type: string
            coordinates:
              type: array
              items:
                type: number
        source:
          type: string
          example: "noaa"

    GeofenceCheckResult:
      type: object
      properties:
        geofence:
          type: object
          properties:
            id:
              type: string
            name:
              type: string
        distance_from_center_km:
          type: number
          format: double
        active_alerts_inside:
          type: integer
        alerts:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              category:
                type: string
              severity:
                type: string
              title:
                type: string

    ResponseMeta:
      type: object
      properties:
        request_id:
          type: string
          description: Unique request identifier for debugging
          example: "req_f1e2d3c4"
        latency_ms:
          type: integer
          description: Server-side processing time in milliseconds
          example: 47

    Pagination:
      type: object
      properties:
        has_more:
          type: boolean
          description: Whether more results exist beyond this page
        next_cursor:
          type: string
          nullable: true
          description: Cursor to pass in the next request for pagination
        total_count:
          type: integer
          description: Total number of matching results

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Machine-readable error code
              example: "VALIDATION_ERROR"
            message:
              type: string
              description: Human-readable error description
              example: "Request body validation failed"
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  message:
                    type: string
                  received:
                    description: The value that was received (any type)
              description: Field-level validation errors (if applicable)

    # ─── Paginated Responses ──────────────────────────────────────────
    PaginatedAlertResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Alert'
        pagination:
          $ref: '#/components/schemas/Pagination'
        meta:
          $ref: '#/components/schemas/ResponseMeta'

    PaginatedIncidentResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Incident'
        pagination:
          $ref: '#/components/schemas/Pagination'
        meta:
          $ref: '#/components/schemas/ResponseMeta'

    PaginatedGeofenceResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Geofence'
        pagination:
          $ref: '#/components/schemas/Pagination'
        meta:
          $ref: '#/components/schemas/ResponseMeta'

  # ─── Reusable Responses ─────────────────────────────────────────────
  responses:
    BadRequest:
      description: Bad Request — invalid parameters or request body
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "VALIDATION_ERROR"
              message: "Invalid query parameters"
              details:
                - field: "lat"
                  message: "Latitude must be between -90 and 90"
                  received: 200

    Unauthorized:
      description: Unauthorized — missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "UNAUTHORIZED"
              message: "Invalid or missing API key. Include a valid key in the X-API-Key header."

    Forbidden:
      description: Forbidden — API key does not have permission for this operation
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "FORBIDDEN"
              message: "Your API key does not have the required scope for this endpoint. Required: incidents:write"

    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "NOT_FOUND"
              message: "The requested resource was not found"

    RateLimited:
      description: Too Many Requests — rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until rate limit resets
          example: 23
        X-RateLimit-Limit:
          schema:
            type: integer
          example: 1000
        X-RateLimit-Remaining:
          schema:
            type: integer
          example: 0
        X-RateLimit-Reset:
          schema:
            type: integer
          example: 1720972800
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "RATE_LIMITED"
              message: "Rate limit exceeded. Upgrade your plan or wait before retrying."

    InternalError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: "INTERNAL_ERROR"
              message: "An unexpected error occurred. Please try again or contact support if the issue persists."
