{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/smarterweather-com/json-schema/smarterweather-com-alert-detail-schema.json",
  "title": "AlertDetail",
  "description": "Full alert representation returned by `GET /v1/alerts/{id}`.\nSupersets `Alert` with full description, instruction, geometry,\nspatial metadata (centroid, recommended zoom, affected\npopulation), the upstream NWS VTEC identifier, and path-impact\n(`pois`, `buildings`) when it was computed.\n",
  "x-generated": "2026-10-30",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/smarterweather-com-openapi.yaml#/components/schemas/AlertDetail",
  "type": "object",
  "required": [
    "group_id",
    "message_id",
    "status",
    "event",
    "severity",
    "urgency",
    "certainty",
    "headline",
    "sender",
    "effective",
    "expires",
    "onset",
    "ends",
    "expiration"
  ],
  "properties": {
    "group_id": {
      "type": "string",
      "description": "The alert's canonical id, stable across its updates (the NWS\nid of its first message).\n"
    },
    "message_id": {
      "type": "string",
      "description": "NWS-issued message identifier (matches `Alert.id`)."
    },
    "status": {
      "type": "string",
      "description": "Alert lifecycle status (e.g., `Actual`, `Exercise`, `Test`)."
    },
    "event": {
      "type": "string"
    },
    "severity": {
      "type": "string",
      "enum": [
        "Extreme",
        "Severe",
        "Moderate",
        "Minor",
        "Unknown"
      ]
    },
    "urgency": {
      "type": "string",
      "enum": [
        "Immediate",
        "Expected",
        "Future",
        "Past",
        "Unknown"
      ]
    },
    "certainty": {
      "type": "string",
      "enum": [
        "Observed",
        "Likely",
        "Possible",
        "Unlikely",
        "Unknown"
      ]
    },
    "headline": {
      "type": "string"
    },
    "description": {
      "type": "string",
      "description": "Multi-paragraph human-readable forecast / hazard\ndescription. Line endings vary by NWS office; clients\nshould treat as opaque text.\n"
    },
    "instruction": {
      "type": "string",
      "description": "Recommended actions (NWS-issued instruction text)."
    },
    "sender": {
      "type": "string",
      "description": "Issuing NWS office identifier."
    },
    "effective": {
      "type": "string",
      "format": "date-time"
    },
    "expires": {
      "type": "string",
      "format": "date-time"
    },
    "onset": {
      "type": "string",
      "format": "date-time"
    },
    "ends": {
      "type": "string",
      "format": "date-time"
    },
    "expiration": {
      "type": "string",
      "format": "date-time",
      "description": "Final expiration time used for cache invalidation."
    },
    "area_desc": {
      "type": "string",
      "description": "Human-readable affected area."
    },
    "highlights": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "Map of salient callouts extracted from the alert text\n(e.g., `{\"hazard\": \"Strong winds\", \"impact\": \"Loose debris possible\"}`).\n"
    },
    "geometry": {
      "type": "object",
      "description": "GeoJSON geometry (Polygon / MultiPolygon) for the affected\narea when stored upstream. Treat as opaque GeoJSON;\nforward-compat fields the pipeline adds without a sw-api\nrelease pass through unchanged.\n",
      "additionalProperties": true
    },
    "centroid_lat": {
      "type": "number",
      "format": "double",
      "description": "Centroid latitude of the affected geometry."
    },
    "centroid_lon": {
      "type": "number",
      "format": "double",
      "description": "Centroid longitude of the affected geometry."
    },
    "recommended_zoom": {
      "type": "integer",
      "description": "Suggested map zoom level when rendering the alert detail."
    },
    "affected_population": {
      "type": "integer",
      "description": "Estimated population intersecting the alert geometry."
    },
    "timezone": {
      "type": "string",
      "description": "IANA timezone of the affected area (e.g., `America/Chicago`)."
    },
    "vtec_id": {
      "type": "string",
      "description": "Upstream NWS VTEC identifier (when present). Useful for\njoining against external VTEC datasets; `null` for alerts\nwithout a VTEC code.\n"
    },
    "event_ending_time": {
      "type": "string",
      "description": "Optional ending-time hint. Currently always omitted; clients\nshould fall back to `expires`. Reserved for forward-compat.\n"
    },
    "pois": {
      "type": "object",
      "description": "Civic POIs inside the alert polygon, computed once when the\nalert is written and stored on the alert.\nPresent only when the request includes `include=impact`.\n`features` are capped at 50. Omitted when unavailable\n(null geometry, timeout, or estimate error) or when impact\nwas not requested. Empty `counts`/`features` means computed\nzero, not unknown.\n",
      "properties": {
        "counts": {
          "type": "object",
          "additionalProperties": {
            "type": "integer"
          }
        },
        "features": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "class": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "buildings": {
      "type": "object",
      "description": "ACS housing units and Overture building-class counts inside\nthe alert polygon, computed once\nwhen the alert is written and stored on the alert.\nPresent only when the request includes `include=impact`.\n`housing_unit` is ACS B25001, not residences. Class keys\n(`residential`, `commercial`, `industrial`, `civic`,\n`other`) appear only when building-class data is available.\n`features` is currently always empty. Omitted when\nunavailable (no housing data, timeout, or estimate\nerror) or when impact was not requested.\n`counts.housing_unit: 0` is computed zero, not unknown.\n",
      "properties": {
        "counts": {
          "type": "object",
          "properties": {
            "housing_unit": {
              "type": "integer"
            },
            "residential": {
              "type": "integer"
            },
            "commercial": {
              "type": "integer"
            },
            "industrial": {
              "type": "integer"
            },
            "civic": {
              "type": "integer"
            },
            "other": {
              "type": "integer"
            }
          }
        },
        "features": {
          "type": "array",
          "items": {
            "type": "object"
          }
        }
      }
    },
    "representative_place": {
      "x-stability": "experimental",
      "allOf": [
        {
          "$ref": "#/$defs/AlertRepresentativePlace"
        }
      ],
      "description": "**Experimental** (`x-stability: experimental`): excluded from the\n90-day breaking-change commitment; the selection rule may be\ntuned.\n\nA named point inside the alert area, for landing a map or a\nlocation page on the alert. `source: census_place` is the most\npopulous Census place inside the area; otherwise\n`source: area_point` is a point inside the area named for its\nzone. Omitted when the alert has no geometry, when no name\nresolves, or when the value is unavailable. Independent of\n`areas`: either can be present without the other.\n\nDetail-only: never returned by `GET /v1/alerts`, including\nas-of (`at=`) reads.\n"
    },
    "areas": {
      "x-stability": "experimental",
      "type": "array",
      "description": "**Experimental** (`x-stability: experimental`): excluded from the\n90-day breaking-change commitment.\n\nOne entry per UGC code the alert names, in first-seen order.\nDerived from the alert's UGC codes only: deduplicated (so\n`areas[i]` does not pair with a raw UGC list or an\n`area_desc` segment), and present even when\n`representative_place` is not. A code the platform cannot\nresolve is named by its UGC and has no `lat`/`lon`. A\nresolved zone, marine zones included, carries a point inside\nboth the zone and the alert's area, so the point's location\npage shows the alert; it has no `lat`/`lon` when the zone does\nnot overlap the alert's area, or when no such point could be\ncomputed.\nOmitted when no usable entry exists (an alert with no UGC\ncodes included) or when the value is unavailable; clients\nfall back to `area_desc`.\n\nTypically a handful of entries; can reach about 100 for large\nadvisories (at most 1000).\n\nDetail-only: never returned by `GET /v1/alerts`, including\nas-of (`at=`) reads.\n",
      "maxItems": 1000,
      "items": {
        "$ref": "#/$defs/AlertArea"
      }
    }
  },
  "$defs": {
    "AlertArea": {
      "type": "object",
      "x-stability": "experimental",
      "description": "**Experimental** (`x-stability: experimental`): excluded from the\n90-day breaking-change commitment.\n\nOne UGC zone of an alert. See `AlertDetail.areas`. `lat` and\n`lon` are present together or not at all. When present, the point\nlies inside both the zone and the alert's area.\n",
      "required": [
        "ugc",
        "name"
      ],
      "dependentRequired": {
        "lat": [
          "lon"
        ],
        "lon": [
          "lat"
        ]
      },
      "properties": {
        "ugc": {
          "type": "string",
          "description": "NWS UGC code (zone `..Z###` or county `..C###`)."
        },
        "name": {
          "type": "string",
          "description": "Zone name; the UGC itself when the code is unresolved."
        },
        "lat": {
          "type": "number",
          "format": "double",
          "description": "Latitude of a point inside both the zone and the alert's area.\nOmitted, with `lon`, for a UGC code the platform cannot\nresolve, for a zone that does not overlap the alert's area, and\nwhen no such point could be computed.\n"
        },
        "lon": {
          "type": "number",
          "format": "double",
          "description": "Longitude of a point inside both the zone and the alert's area; omitted with `lat`."
        }
      }
    },
    "AlertRepresentativePlace": {
      "type": "object",
      "x-stability": "experimental",
      "description": "**Experimental** (`x-stability: experimental`): excluded from the\n90-day breaking-change commitment.\n\nA named point inside an alert area. See `AlertDetail.representative_place`.\n",
      "required": [
        "name",
        "lat",
        "lon",
        "source"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "Census place name with state (`census_place`), or the zone\nname for an `area_point`.\n"
        },
        "lat": {
          "type": "number",
          "format": "double"
        },
        "lon": {
          "type": "number",
          "format": "double"
        },
        "population": {
          "type": "integer",
          "description": "Census population of the place. Present only for\n`source: census_place` when the Census row carries one.\n"
        },
        "source": {
          "type": "string",
          "enum": [
            "census_place",
            "area_point"
          ],
          "description": "`census_place`: the most populous Census place inside the\nalert area. `area_point`: a point inside the area named for\nthe zone that contains it (or the alert's first area).\n"
        }
      }
    }
  }
}