# Weather API Integration Weatherreporter fetches normalized weather inputs from a configured Weather API base URL. This guide defines the HTTP contract the service must satisfy; it is not a general Weather API reference. Configuration values are defined in the [configuration reference](../config.md). Normalization and collection behavior are documented in [Weather data internals](../internal/weather-data.md) and [Collection internals](../internal/collect.md). ## Base URL And Requests `weather_api.base_url` must be an absolute URL. Weatherreporter joins each endpoint path to the configured base URL path, so a service hosted under a path prefix must keep that prefix available. Requests use `GET` and carry the configured timeout on every HTTP attempt. Every request sends `format` and, except where noted below, `units`. The configured format must be `json`. Before retrieving sources, Weatherreporter warms up `/conditions/current` with the same `format`, `units`, and `precision` query parameters used for current conditions. The warmup only requires a readable 2xx response; its body is not decoded. Failure after its internal retry budget stops the fetch before source requests begin. ## Endpoints And Query Parameters The adapter makes one source request for each endpoint after a successful warmup, subject to retry on transient failures. | Source | Endpoint | Query parameters | Availability | | --- | --- | --- | --- | | Observations | `/observations` | `format`, `units`, `precision` | Optional | | Current conditions | `/conditions/current` | `format`, `units`, `precision` | Optional | | Hourly forecast | `/forecast/hourly` | `format`, `units`, `precision`, `tz` | Required | | Narrative forecast | `/forecast/narrative` | `format`, `units`, `precision`, `tz` | Optional | | Active alerts | `/alerts/active` | `format`, `units` | Optional; `data: null` means checked with no active alerts | | Forecast discussion | `/discussion` | `format`, `units`, `tz` | Optional | | Weather story | `/weatherstories/latest` | `format` | Optional | | SPC convective outlooks | `/outlooks/convective` | `format`, `tz` | Optional; non-null empty lists are checked empty data | `precision` comes from `weather_api.precision`; `tz` comes from `weather_api.timezone`. Weatherreporter does not call day-slice forecast or discussion-subsection endpoints. ## Response Envelope Each endpoint response must be JSON with a top-level `data` member: ```json { "data": {} } ``` An absent `data` member is treated as a missing source. For ordinary sources, `data: null` is also missing. The active-alert exception is listed above: its explicit `null` payload represents an empty alert result. Hourly forecast data must be present and contain at least one `period`; a missing, malformed, or empty hourly product fails collection. The remaining sources follow the configured missing-source policy. Under `error`, collection fails; under `warn`, the source is omitted and an inspectable warning is recorded; under `none`, the source is omitted without a warning. A per-source policy overrides the default. See [Configuration](../config.md) for policy settings and [Weather data internals](../internal/weather-data.md) for recorded source metadata. Malformed top-level JSON envelopes and HTTP failures are direct request errors. Malformed `data` for an optional source follows its missing-source policy. ## Payload Fields Used Weatherreporter decodes only the fields below; additional upstream fields are ignored. Timestamps must be JSON values accepted by Go's `time.Time` decoder. ### Observations And Current Conditions `/observations` uses `stationId`, `stationName`, `timestamp`, `conditionCode`, `isDay`, `textDescription`, `temperatureC`, `temperatureF`, `dewpointC`, `dewpointF`, `windSpeedKmh`, `windSpeedMph`, `windGustKmh`, `windGustMph`, `windDirectionDegrees`, `barometricPressurePa`, `barometricPressureInHg`, `visibilityMeters`, `visibilityMiles`, `relativeHumidityPercent`, `apparentTemperatureC`, `apparentTemperatureF`, and `presentWeather`. `/conditions/current` uses `conditionText`, `isDay`, `relativeHumidityPercent`, `windDirectionDegrees`, `temperatureC`, `temperatureF`, `apparentTemperatureC`, `apparentTemperatureF`, `dewpointC`, `dewpointF`, `windSpeedKmh`, and `windSpeedMph`. ### Hourly And Narrative Forecasts Both forecast endpoints use run-level `locationId`, `locationName`, `issuedAt`, `updatedAt`, `product`, `latitude`, `longitude`, `elevationMeters`, `elevationFeet`, and `periods`. Each `periods` item uses `startTime`, `endTime`, `name`, `isDay`, `conditionCode`, `textDescription`, `temperatureC`, `temperatureF`, `temperatureCMin`, `temperatureFMin`, `temperatureCMax`, `temperatureFMax`, `dewpointC`, `dewpointF`, `windSpeedKmh`, `windSpeedMph`, `windGustKmh`, `windGustMph`, `windDirectionDegrees`, `barometricPressurePa`, `barometricPressureInHg`, `visibilityMeters`, `visibilityMiles`, `apparentTemperatureC`, `apparentTemperatureF`, `cloudCoverPercent`, `probabilityOfPrecipitationPercent`, `precipitationAmountMm`, `precipitationAmountIn`, `snowfallDepthMM`, `snowfallDepthIn`, `uvIndex`, and `relativeHumidityPercent`. ### Alerts, Discussion, And Weather Story `/alerts/active` uses the `asOf` timestamp and keeps each item in `alerts` as an alert payload. Weatherreporter does not require a separate alert-item schema at this integration boundary. `/discussion` uses `officeId`, `officeName`, `product`, `issuedAt`, `updatedAt`, `keyMessages`, and the `shortTerm` and `longTerm` sections. Each section uses `qualifier`, `text`, and `issuedAt`. `/weatherstories/latest` uses `officeId`, `startTime`, `endTime`, `updatedAt`, `title`, `description`, `altText`, `priority`, `order`, and `downloadUrl`. ### SPC Convective Outlooks `/outlooks/convective` uses run-level `locationId`, `locationName`, `asOf`, `issuedAt`, `updatedAt`, `product`, `outlooks`, and `discussions`. Each outlook uses `id`, `provider`, `product`, `day`, `outlookType`, `label`, `labelText`, `forecaster`, `severityRank`, `validFrom`, `validTo`, `issuedAt`, `expiresAt`, `sourceUrl`, `imageUrl`, `containsLocation`, and GeoJSON `geometry`. Each discussion uses `day`, `headline`, `summary`, `discussion`, and `updatedAt`. ## Timeouts, Retries, And Failures The configured Weather API timeout applies to each warmup and source HTTP attempt. Weatherreporter retries transient transport and response-read failures and these response statuses: `408`, `429`, `500`, `502`, `503`, and `504`. It does not retry other HTTP statuses, malformed envelopes, missing data, or payload decoding failures. A canceled context also stops an in-progress retry delay. The adapter reads at most 10 MiB from one response body. A non-2xx response, request construction failure, read failure, or decode failure includes endpoint context in its error. Retry counts and delays are adapter behavior rather than Weather API request parameters. Do not depend on a particular attempt count when implementing the service.