API reference
Every public route on the Aeroza v1 API, organised by domain. Use this page when you want a one-screen survey of the surface; use the interactive explorer when you want to inspect schemas and send requests directly from the page.
Three ways to drive the API interactively:
- /docs/api/explorer — the embedded Scalar reference (recommended). Themed to match the rest of the site, three-column layout, code samples in shell / JS / Python out of the box.
- https://aerozasdk-production.up.railway.app/docs — FastAPI's built-in Swagger UI. Plain but always 1:1 with the server's current shape.
- https://aerozasdk-production.up.railway.app/openapi.json — the raw OpenAPI schema. Point any codegen tool at it.
Conventions
- JSON only on the wire, with
camelCasefield aliases on response payloads. The internal Python is snake_case; pydantic re-aliases at the boundary. - Geospatial ordering follows GeoJSON / OGC.
bboxandpolygonuselng,lat,lng,lat,…;pointuseslat,lngfor human-friendliness. - Times are ISO-8601 UTC. When an endpoint returns a
validAtormaterialisedAt, expect aZsuffix. - Errors are FastAPI-shaped: JSON body with a
detailfield. Out-of-domain queries return 404 with a human-readable detail; validation failures return 422.
Health & meta
| Route | Summary |
|---|---|
GET /health | Liveness check. Returns version + status. No DB or NATS dependency. |
GET /v1/stats | Compact 'what does the system know right now?' snapshot. Alert counts, MRMS file/grid counts, freshness watermarks. |
GET /v1/me | Introspect the calling API key (name, owner, scopes, last-used). Requires Authorization: Bearer aza_live_*. Mint keys with the aeroza-api-keys CLI; the operator's only management plane in v1. |
Alerts
| Route | Summary |
|---|---|
GET /v1/alerts | List active NWS alerts as a GeoJSON FeatureCollection. Filter by point, bbox, or minimum severity. |
GET /v1/alerts/stream | Server-Sent Events feed re-emitting newly observed alerts. One event per row published on aeroza.alerts.nws.new. |
GET /v1/alerts/{alert_id} | Single-alert detail with description + instruction. Includes alerts whose `expires` is in the past. |
MRMS — catalog & grids
| Route | Summary |
|---|---|
GET /v1/mrms/files | MRMS file catalog — what data is available right now. Filter by product, level, and a [since, until) window. |
GET /v1/mrms/grids | Materialised-grid catalog — what data is queryable right now. Same filters as /v1/mrms/files; result is locator-shaped. |
GET /v1/mrms/grids/{file_key} | One materialised grid by its source S3 key. |
MRMS — queries
| Route | Summary |
|---|---|
GET /v1/mrms/grids/sample | Nearest-cell value at a (lat, lng). Defaults to the latest grid; pass at_time to reduce a grid valid at-or-before that moment. |
GET /v1/mrms/grids/polygon | Reduce a grid over a polygon (max / mean / min / count_ge). Polygon vertices on lng,lat,lng,lat,…; ring implicitly closed; count_ge requires a numeric threshold. |
GET /v1/mrms/tiles/{z}/{x}/{y}.png | Web-Mercator XYZ raster tile of the latest matching MRMS grid. 256×256 PNG with the standard NWS dBZ ramp; transparent fallback when no grid is materialised. Pass fileKey to pin a specific source. Cache-Control: max-age=60. |
METAR (surface observations)
| Route | Summary |
|---|---|
GET /v1/metar | List recent METAR observations, newest first. Filter by station (case-insensitive ICAO id), since, until, bbox (min_lng,min_lat,max_lng,max_lat), and limit (default 100, max 500). Sourced from aviationweather.gov; rows include parsed temp/wind/visibility plus the raw METAR text for custom parsers. |
GET /v1/metar/{station_id}/latest | Most-recent observation for one ICAO station. Case-insensitive on the path. 404 when the station has no observations. |
Nowcasts & calibration
| Route | Summary |
|---|---|
GET /v1/nowcasts | Predicted-grid catalog (algorithm × forecast horizon). Filter by product, level, algorithm (e.g. 'persistence'), horizonMinutes, and a [since, until) window on validAt. |
GET /v1/calibration | Aggregate verification metrics, grouped by algorithm × horizon. Sample-weighted MAE / bias / RMSE plus categorical POD / FAR / CSI (at the verifier's threshold, default 35 dBZ) over the window. Default windowHours=24; supports algorithm / product / level filters. |
GET /v1/calibration/series | Time-bucketed companion to /v1/calibration — sparkline per (algorithm, horizon). Same metrics (continuous + categorical), with one extra group-by on bucketStart. bucketSeconds in [300, 86400] (default 3600 / 1 hour). |
Webhooks
| Route | Summary |
|---|---|
GET /v1/webhooks | List webhook subscriptions. Filter by status (active / paused / disabled). The list omits the secret; the detail route returns its hash. |
POST /v1/webhooks | Create a subscription. Body: target URL, events array (e.g. aeroza.alerts.nws.new, aeroza.nowcast.grids.new), an optional alertRuleId, optional secret (auto-generated if omitted). |
GET /v1/webhooks/{sub_id} | One subscription's full detail. |
PATCH /v1/webhooks/{sub_id} | Update events / target / status / alertRuleId. Status transitions: active ⇄ paused; the dispatcher's circuit breaker can flip a sub to disabled after repeated 4xx/5xx. |
DELETE /v1/webhooks/{sub_id} | Soft-delete a subscription. Sets status to deleted; rows are kept so the delivery log remains queryable. |
GET /v1/webhooks/{sub_id}/deliveries | Recent delivery attempts for a subscription. Read-only audit trail — one row per attempt the dispatcher made (initial + retries), newest-first. Optional status filter (ok / failed / retrying). The signed payload itself is omitted from the wire. |
Alert rules (webhook predicate DSL)
| Route | Summary |
|---|---|
GET /v1/alert-rules | List alert rules. Rules are reusable across webhook subscriptions — one rule, many subs. The wire shape is a discriminated union over rule.kind (currently 'point' or 'polygon'). |
POST /v1/alert-rules | Create a rule. Body: kind, predicate config (point: lat/lng/radiusMeters; polygon: GeoJSON-style coordinates), severity floor, optional event-name allowlist. |
GET /v1/alert-rules/{rule_id} | One rule's full detail. |
PATCH /v1/alert-rules/{rule_id} | Update predicate / severity floor / status. |
DELETE /v1/alert-rules/{rule_id} | Soft-delete a rule. |
Stable contract?
v1 is the contract shape we're committing to — JSON envelope, camelCase aliases, GeoJSON ordering. Adding new fields to a response payload is non-breaking; removing or renaming will bump the route to /v2. The TypeScript SDK (@aeroza/sdk) pins the wire types so consumers get a compile-time signal when something changes; the dev console at /console is the same SDK driving every panel, so any awkwardness in the contract shows up in the SDK first.